【问题标题】:Android - Expandable ListView - using ViewHolder for optimizationAndroid - Expandable ListView - 使用 ViewHolder 进行优化
【发布时间】:2014-03-22 21:15:33
【问题描述】:

我有一个 ListView,其中每一行都是图像+文本。我已经使用 ViewHolder 将这个列表实现为一个单独的列表来优化滚动。 现在我尝试使用相同的视觉效果,但这次是作为可扩展列表视图的一部分。我这样做了,虽然在视觉上看起来一样,但滚动自然是粘性的……所以问题是:

如何在 Expandable ListView 中使用 ViewHolder 技术?

我认为必须在 getChildView() 方法中完成某些操作,但我对这种技术的经验不足,无法自己弄清楚细节。这是适配器和子布局。任何帮助将不胜感激!

 public class MyExpandableListAdapter2 extends BaseExpandableListAdapter {



  private final SparseArray<Group> groups;
  public LayoutInflater inflater;
  public Activity activity;

  public MyExpandableListAdapter2(Activity act, SparseArray<Group> groups) {
    activity = act;
    this.groups = groups;
    inflater = act.getLayoutInflater();
  }

  @Override
  public Object getChild(int groupPosition, int childPosition) {
    return groups.get(groupPosition).children.get(childPosition);
  }

  @Override
  public long getChildId(int groupPosition, int childPosition) {
    return 0;
  }

  @Override
  public View getChildView(int groupPosition, final int childPosition,
      boolean isLastChild, View convertView, ViewGroup parent) {
        final String children = (String) getChild(groupPosition, childPosition);
        convertView = inflater.inflate(R.layout.listrow_details2, null);
        text = (TextView) convertView.findViewById(R.id.expandable_list_child_view2);

        // Complicated code where I create a bitmap programmatically and set
        // it as drawable on the TextView along with the appropriate text.

    return convertView;
  }

  @Override
  public int getChildrenCount(int groupPosition) {
    return groups.get(groupPosition).children.size();
  }

  @Override
  public Object getGroup(int groupPosition) {
    return groups.get(groupPosition);
  }

  @Override
  public int getGroupCount() {
    return groups.size();
  }

  @Override
  public void onGroupCollapsed(int groupPosition) {
    super.onGroupCollapsed(groupPosition);
  }

  @Override
  public void onGroupExpanded(int groupPosition) {
    super.onGroupExpanded(groupPosition);
  }

  @Override
  public long getGroupId(int groupPosition) {
    return 0;
  }

  @Override
  public View getGroupView(int groupPosition, boolean isExpanded,
      View convertView, ViewGroup parent) {
    if (convertView == null) {
      convertView = inflater.inflate(R.layout.listrow_group2, null);
    }
    Group group = (Group) getGroup(groupPosition);
    ((TextView) convertView).setText(group.string);
    ((TextView)  convertView).setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_launcher, 0, 0, 0);



    //((TextView) convertView).setChecked(isExpanded);

    return convertView;
  }

  @Override
  public boolean hasStableIds() {
    return false;
  }

  @Override
  public boolean isChildSelectable(int groupPosition, int childPosition) {
    return true;
  }

} 

子布局:listrow_details2.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:paddingLeft="40dp" >

    <TextView
        android:id="@+id/expandable_list_child_view2"
        android:clickable="true"
        android:background="@layout/transparent_text_selector"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:drawablePadding="5dp"
        android:gravity="top|left"
        android:text="@string/hello_world"
        android:textSize="14sp" >
    </TextView>

   <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="#d3d3d3" />

</LinearLayout> 

【问题讨论】:

  • 视图持有者对性能的影响很小,我不知道为什么人们真正使用它
  • 从我读到的内容来看,它提高了 15% 的性能......除此之外,我发现两种方法之间的滚动平滑度有所不同,所以我想它会产生足够的影响陷入困境......
  • 加油,SimpleCursorAdapter 不使用任何支架,但它足够快

标签: android expandablelistview expandablelistadapter


【解决方案1】:

您将要使用 2 个不同的视图持有者。首先,让我们定义一个 ViewHolder 类。

public class ViewHolder
{
    private HashMap<Integer, View> storedViews = new HashMap<Integer, View>();

    public ViewHolder()
    {
    }

    /**
     * 
     * @param view
     *            The view to add; to reference this view later, simply refer to its id.
     * @return This instance to allow for chaining.
     */
    public ViewHolder addView(View view)
    {
        int id = view.getId();
        storedViews.put(id, view);
        return this;
    }

    public View getView(int id)
    {
        return storedViews.get(id);
    }
}

我们想在getGroupView 方法和getChildView 方法中使用ViewHolder。

    @Override
    public View getChildView(int groupPosition, final int position,
           boolean isLastChild, View convertView, ViewGroup parent)
    {
        View row = convertView;
        if (row == null)
        {
            row = inflater.inflate(R.layout.my_layout_for_row, parent, false);
            View myView = row.findViewById(R.id.myView);
            ViewHolder holder = new ViewHolder();
            holder.addView(myView);
            row.setTag(holder);
        }

        // Get the stored ViewHolder that also contains our views
        ViewHolder holder = (ViewHolder) row.getTag();
        View myView = holder.getView(R.id.myView);
        return row;
    }

我们对 groupView 方法做同样的事情。

@Override
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent)
    {
        View v = convertView;
        if (v == null)
        {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = inflater.inflate(R.layout.my_layout, parent, false);
            ViewHolder holder = new ViewHolder();
            holder.addView(v.findViewById(R.id.myView));
            v.setTag(holder);
        }

        ViewHolder holder = (ViewHolder) v.getTag();
        // Do whatever you need to with the group view
        return v;
    }

编辑:也许需要对 ViewHolder 的实际工作方式进行一些解释。

if(row == null) 中的代码仅用于第一次初始化视图。每当新行想知道要使用什么布局时,这个视图就会在 convertView 字段中传递。我们在这个被传递的视图上设置了 ViewHolder,这样我们就不必每次都调用 findViewById 或膨胀布局,这两者都是相对昂贵的操作。因此,当转换视图不为空时,它不会进入那个 if 语句,我们所关心的只是为 ViewHolder 中包含的视图设置自定义值。

【讨论】:

  • 所以我执行创建位图和设置文本的“复杂代码”的部分是在 if(v==null) 内完成的?
  • 不完全。 if 语句中的那部分仅用于第一次初始化视图。每当新行想知道要使用什么布局时,这个视图就会在 convertView 字段中传递。我们在这个被传递的视图上设置了 ViewHolder,这样我们就不必每次都调用 findViewById 或膨胀布局,这两者都是相对昂贵的操作。因此,当转换视图不为空时,它不会进入那个 if 语句,我们只关心它之后。
  • 当我使用接受的答案时,我得到的 edittext 的内容在另一个组内的另一个 edittext 中重复,我该如何解决?
  • 太好了,这给了我一个想法,我想使用可扩展列表视图与 Kotin 中的异构组和子项使用数据绑定来实现。很酷的东西!
  • 这将在添加视图之前创建 ViewHolder 的新实例。所以每个 ViewHolder 都会有一个 HashMap,最多包含一个视图。将 ViewHolder 的实例作为列表适配器的成员变量会更有意义。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-04-16
  • 1970-01-01
  • 1970-01-01
  • 2017-04-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多