【发布时间】:2010-11-22 04:07:26
【问题描述】:
我将数据从光标加载到列表视图,但我的列表视图并没有真正显示“流畅”。当我在 ListView 的 scollbar 上上下拖动时,数据会发生变化。有些项目看起来像在我的列表中重复显示。 我有一个“复杂的 ListView”(两个 textview,一个 imageview)所以我使用 newView()、bindView() 来显示数据。有人可以帮我吗?
【问题讨论】:
我将数据从光标加载到列表视图,但我的列表视图并没有真正显示“流畅”。当我在 ListView 的 scollbar 上上下拖动时,数据会发生变化。有些项目看起来像在我的列表中重复显示。 我有一个“复杂的 ListView”(两个 textview,一个 imageview)所以我使用 newView()、bindView() 来显示数据。有人可以帮我吗?
【问题讨论】:
我将向您描述如何解决您遇到的此类问题。这可能会对您有所帮助。
所以,在列表适配器中你有这样的代码:
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);
}
您将拥有当前的应用程序行为与列表项重复。
可能会有帮助。
【讨论】:
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
从他的谈话中,并根据我自己的经验按重要性排序,
【讨论】:
我也遇到了这个问题,但就我而言,我使用线程来获取外部图像。重要的是当前执行的线程不要改变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();
如果他们的视图被重用,也可以取消当前线程(就像 here 所描述的那样),但我决定不这样做,因为我想填充我的缓存以供以后重用。
【讨论】:
只有一个提示:切勿使用项目布局的透明背景 - 它会大大降低性能
【讨论】:
如果您以错误的方式处理它,您可以在多行中看到重复出现的文本。我最近写了一些关于它的博客 - 请参阅here。除此之外,您可能想看看ListView performance optimization。通常是因为视图重用,我已经看过几次了。
【讨论】: