【问题标题】:Improve performance of ListView assignation提高 ListView 分配的性能
【发布时间】:2014-01-07 21:23:57
【问题描述】:

我已关注this、this 和this,以使我的 ListView 具有尽可能好的性能。实际上,在第三个链接之后,我大大提高了滚动的流畅度。

问题是我为每一行使用自定义布局,其中包含 2 个 ImageView(其中一个不变,第二个具有两个可能的可绘制对象分配)和两个 TextView,所以这是定义:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/elem_list"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/chanlist_featured"
        android:layout_width="20dp"
        android:layout_height="30dp"
        android:layout_marginTop="8dp"
        android:contentDescription="@string/desc_gen_image"
        android:gravity="center" />

    <TextView
        android:id="@+id/chanlist_chan"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_gravity="left"
        android:layout_weight="13"
        android:ellipsize="marquee"
        android:maxLines="2"
        android:padding="10dp" />

    <LinearLayout 
      android:layout_width="40dp"
      android:layout_height="match_parent"
      android:orientation="vertical">

      <TextView
        android:id="@+id/chanlist_usercount"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:paddingTop="10dp"
        android:ellipsize="marquee"
        android:gravity="center"
        android:maxLines="2"
        android:textSize="11sp" />

      <ImageView
        android:layout_width="10dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:paddingTop="8dp"
        android:contentDescription="@string/desc_gen_image"
        android:background="@drawable/user" />

    </LinearLayout>
</LinearLayout>

好的,到目前为止没问题。所以我定义了我自定义的 ArrayAdapter,它的 getView() 方法如下:

// This is the public class for the ViewHolder object
public static class vhItem {
  TextView maintext; 
  ImageView mainimage;
  TextView users; 
}

@Override
public View getView(final int position, View convertView, final ViewGroup parent) {
  vhItem viewHolder;

  if (convertView == null) {
    final LayoutInflater inflater = ((Activity) context).getLayoutInflater();
    convertView = inflater.inflate(resourceId, parent, false);

    viewHolder = new vhItem();
    viewHolder.maintext = (TextView) convertView.findViewById(R.id.chanlist_chan);
    viewHolder.mainimage = (ImageView) convertView.findViewById(R.id.chanlist_featured);
    viewHolder.users = (TextView) convertView.findViewById(R.id.chanlist_usercount);

    convertView.setTag(viewHolder);      
  }
  else
    viewHolder = (vhItem) convertView.getTag();

  final InfoCanal chaninfo = (InfoCanal) getItem(position);

  viewHolder.maintext.setText(chaninfo.getChanName() + "\n" + chaninfo.getTopic());        
  viewHolder.users.setText(String.valueOf(chaninfo.getUserCount()));

  /* star and star_off are the two Drawable objects that I initialized in the constructor of
     the class, so I don't have to findViewById() them each time I call this method */
  if (chaninfo.getFeatured())
    viewHolder.mainimage.setImageDrawable(star);
  else
    viewHolder.mainimage.setImageDrawable(star_off);

  return convertView; 
}

问题来了:我试图显示大约 300 个列表元素。正如我所说,列表滚动顺畅(我发现的大多数关于提高 ListViews 性能的帖子都在谈论这一点),但是适配器的初始化调用(new MyOwnArrayAdapter() ...)和可视化之间的时间列表很大(大约 15-20 秒)。我可以简单地修饰它显示一个进度条,但我想知道我是否在这里做一些低效的事情,因为我认为 300 个元素并没有那么多。

任何建议表示赞赏!

--------- 编辑 ----------

我包括构造函数:

public class StableArrayAdapter<T> extends ArrayAdapter<T> {
  final private Context context;
  final private int resourceId; 
  final private List<T> objects;
  final Drawable star, star_off;

  // There I store the objects to include in the list
  final private HashMap<T, Integer> mIdMap = new HashMap<T, Integer>();
  // I had to Override some methods related to the observers, that's why I store this
  final private ArrayList<DataSetObserver> observers = new ArrayList<DataSetObserver>();

  // Constructor
  public StableArrayAdapter(final Context context_, final int resourceId_, final List<T> objects_) {
    super(context_, resourceId_, objects_);

    this.context = context_;
    this.resourceId = resourceId_;
    this.objects = objects_;

    for (int i = 0; i < objects.size(); i++)
      mIdMap.put(objects.get(i), i);

    star = context.getResources().getDrawable(R.drawable.checkbox_star);
    star_off = context.getResources().getDrawable(R.drawable.checkbox_star_down);
  }

  ...
}

【问题讨论】:

  • 如果滚动不是问题,那么您的问题不在getView()。它在您的适配器初始化中。您如何获取填充 ListView 的数据?将此代码添加到您的帖子中。
  • 传递给 StableArrayAdapter() 的数据被解析为具有这 300 项定义的 URL。我没有计算这花费的时间,因为它是一个单独的任务(在后台线程中,顺便说一句)。获得这些项目后,我将它们传递给我在帖子中编辑的构造函数。

标签: android performance android-listview android-adapter


【解决方案1】:

只是徘徊-您将 List 转换为 HashMap (使用某种 idex?),而不是在 getView() 中,您执行 getItem(position) 可能会在 HashMap 中搜索 value(!!!) == 位置?为什么不保留原始列表并直接从中获取数据元素?

【讨论】:

  • 如你所见,StableArrayAdapter 类是参数化的(T),这是因为我想将它用于具有相同逻辑但不同数据类型的多个活动,并避免为 ArrayAdapter 定义一个扩展每一个。我使用 HashMap 是因为它非常有效,但对于其中一些活动(不是特别是这一项),我需要有稳定的 Id(即,即使在更新 HashSet 之后元素也必须具有相同的 id)。
【解决方案2】:

我猜问题出在你在构造函数中执行的List 循环中。我想知道是否某些List 实现每次都会遍历其基础数据集以满足size() 方法。那缓存呢?

int size = objects.size();
for (int i = 0; i < size; i++) {
      mIdMap.put(objects.get(i), i);
}

也可以使用Iterator

【讨论】:

  • 根据您的评论,我在该循环之前和之后放置了一个 Log 对象,耗时 0.12 秒。处理它,所以我认为这不是问题。但是,这似乎很奇怪,因为 List 的内容在它离开构造函数后出现几秒钟......
【解决方案3】:

我终于明白了。基本上,它与初始化和 getView() 方法无关。在处理StableArrayAdapter() 构造函数的过程中,我可以并行做一些额外的事情,我在调用new StableArrayAdapter() 之前启动了一个Thread(),并且为了同步这个线程的结果和初始化,我忘记了我已经声明了一个CountDownLatch(),所以基本上适配器初始化下面的代码就是在等待线程调用countDown()方法。

对不起大家,同时感谢你们,从最初的帖子中的代码没有人知道这一点(我无意中省略了这部分,认为这并不重要)。

同时我希望这可以帮助某人,或者至少提供一个线索。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-06
    • 1970-01-01
    • 2019-10-06
    • 1970-01-01
    • 2016-09-06
    • 1970-01-01
    相关资源
    最近更新 更多