提高ListView分配的性能

时间:2014-01-07 21:23:57

标签: android performance android-listview android-adapter

我已关注thisthisthis,以使我的ListView具有最佳性能。实际上,在第三个链接后,我基本上改进了滚动的平滑性。

问题是我正在为每行使用一个自定义布局,其中包含2个ImageView(其中一个不变,第二个有两个可能的drawable分配)和两个TextView,所以这是定义:< / p>

<?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性能的帖子都谈到了这一点),但是适配器初始化调用之间的时间(新的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);
  }

  ...
}

3 个答案:

答案 0 :(得分:0)

只是徘徊 - 你将List转换为HashMap(带有某种idex?),而不是在getView()中你可以使用getItem(position)搜索HashMap的值(!!!)== position?为什么不保留原始列表并从中获取数据元素呢?

答案 1 :(得分:0)

我猜这个问题出现在构造函数中的List循环中。我想知道是否有一些List实现每次都会遍历它们的基础数据集以满足size()方法。缓存那个怎么样?

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

或者可以使用Iterator

答案 2 :(得分:0)

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

我很抱歉,并且同时感谢你们,从最初的帖子中的代码中没有人知道这一点(我无意中忽略了这一部分,认为它并不重要)。

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