如何在安卓中“平滑”地加载Listview

11

我从Cursor加载数据到ListView,但我的ListView并没有真正地“平滑”地显示。当我在ScrollView上向上或向下拖动时,数据会改变。有些条目在我的列表中看起来像是重复显示了。 我有一个“复杂的ListView”(两个TextView,一个ImageView),因此我使用newView()和bindView()来显示数据。 有人可以帮我吗?

5个回答

10

我将向您描述如何获取您遇到的问题。也许这会对您有所帮助。

因此,在列表适配器中,您有以下代码:

public View getView(int position, View contentView, ViewGroup arg2)
    {
        ViewHolder holder;

        if (contentView == null) {
            holder = new ViewHolder();
            contentView = inflater.inflate(R.layout.my_magic_list,null);
            holder.label = (TextView) contentView.findViewById(R.id.label);
            contentView.setTag(holder);
        } else {
            holder = (ViewHolder) contentView.getTag();
        }

        holder.label.setText(getLabel());

        return contentView;
    }

正如您所看到的,我们只有在获取 holder 后才设置列表项值。

但是如果将代码移至上面的 if 语句中:

holder.label.setText(getLabel());
所以它之后会看起来像下面这样:
if (contentView == null) {
   holder = new ViewHolder();
   contentView = inflater.inflate(R.layout.my_magic_list,null);
   holder.label = (TextView) contentView.findViewById(R.id.label);
   holder.label.setText(getLabel());
   contentView.setTag(holder);
}

如果您重复列表项,则您将获得当前应用程序的行为。

可能这会有所帮助。


8

ListView是一个棘手的问题。

先回答你的第二个问题:你看到重复的原因是因为ListView通过convertView重用视图,但你没有确保重置转换视图的所有方面。确保convertView!=null的代码路径正确设置视图的所有数据,一切都应该正常工作。

如果你使用自定义视图,你希望你的getView()方法大致如下:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    final MyCustomView v = convertView!=null ? (MyCustomView)convertView : new MyCustomView();
    v.setMyData( listAdapter.get(position) );
    return v;
}

如果您没有使用自定义视图,只需将调用new MyCustomView()替换为调用inflater.inflate(R.layout.my_layout,null) 至于您的第一个问题,您需要观看Romain在此处关于ListView性能的技术讲座:http://code.google.com/events/io/sessions/TurboChargeUiAndroidFast.html 从他的讲话和根据我的经验,按重要性顺序,
  • 使用convertView
  • 如果您有图片,请不要动态缩放图片。使用Bitmap.createScaledBitmap创建缩放的位图并将其放入视图中
  • 使用ViewHolder,这样您就不必每次都调用一堆findViewByIds()
  • 减少列表视图中视图的复杂性。子视图越少,越好。RelativeLayout比LinearLayout更适合这样做。如果您正在实现自定义视图,请确保使用merge

抱歉,我使用newView()和bindView()来显示数据。这是同样的问题吗? - Dennie
我觉得这个视频很有帮助,谢谢分享! - Dennie

1

我也遇到了这个问题,但在我的情况下,我使用线程来获取外部图像。当前执行的线程不应更改imageView,如果它被重用,这一点非常重要!

public View getView(int position, View vi, ViewGroup parent) {
ViewHolder holder;
String imageUrl = ...;

if (vi == null) {
    vi = inflater.inflate(R.layout.tweet, null);
    holder = new ViewHolder();
    holder.image = (ImageView) vi.findViewById(R.id.row_img);
    ...
    vi.setTag(holder);
} else {
    holder = (ViewHolder) vi.getTag();      
}
holder.image.setTag(imageUrl);
...
DRAW_MANAGER.fetchDrawableOnThread(imageUrl, holder.image);
}

然后在获取线程中,我正在进行重要检查

final Handler handler = new Handler() {
@Override
public void handleMessage(Message message) {
     // VERY IMPORTANT CHECK
    if (urlString.equals(url))
        imageView.setImageDrawable((Drawable) message.obj);
};

Thread thread = new Thread() {  

@Override
public void run() {
    Drawable drawable = fetchDrawable(urlString);
    if (drawable != null) {
        Message message = handler.obtainMessage(1, drawable);
        handler.sendMessage(message);
    }
}};
thread.start();

如果视图被重用(就像这里所描述的那样),也可以取消当前线程,但我决定不这样做,因为我想填充我的缓存以供以后重用。


1
一个小建议:永远不要使用项目布局的透明背景 - 它会极大地降低性能。

0
如果你处理不当,就会在多行中看到重复的文本。我最近写了一篇博客,可以在这里看到。除此之外,你可能想要查看ListView性能优化。通常是因为视图重用的原因,我已经见过几次了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接