我从Cursor加载数据到ListView,但我的ListView并没有真正地“平滑”地显示。当我在ScrollView上向上或向下拖动时,数据会改变。有些条目在我的列表中看起来像是重复显示了。 我有一个“复杂的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
从他的讲话和根据我的经验,按重要性顺序,
merge
我也遇到了这个问题,但在我的情况下,我使用线程来获取外部图像。当前执行的线程不应更改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();
如果视图被重用(就像这里所描述的那样),也可以取消当前线程,但我决定不这样做,因为我想填充我的缓存以供以后重用。