And*_*nko 2 android android-widget listadapter android-listview
我有一个ListView以下适配器:
private class ListAdapter extends BaseAdapter {
private List<Item> items;
private ImageCache imageCache;
public ListAdapter(List<Item> item) {
this.items=items;
imageCache=ImageCache.getInstance();
}
//nothing special here
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = getLayoutInflater().inflate(R.layout.listitem, parent, false);
viewHolder = new ViewHolder();
viewHolder.imgView = (ImageView) convertView.findViewById(R.id.imgview);
viewHolder.txtView = (TextView) convertView.findViewById(R.id.txtview);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
Item item = getItem(position);
//this method is used to start download
imageCache.load(item.getImageURL(), viewHolder.imgView);
viewHolder.txtView.setText(item.getText());
return convertView;
}
}
Run Code Online (Sandbox Code Playgroud)
以下是我的ImageCache课.它依赖于android.util.LruCache杰克沃顿的DiskLruCache ; 如果在内存和磁盘缓存中找不到该项,则使用AsyncTask下载该项.
private Map<String,WeakReference<ImageView>> references;
//...
public void load(String imageUrl, ImageView imgView) {
final String key=getKey(imageUrl);
references.put(key, new WeakReference<ImageView>(imgView));
this.get(imageUrl, new OnImageLoadedListener() {
public void onImageLoaded(Bitmap image) {
WeakReference<ImageView> imgViewRef=references.get(key);
if(imgViewRef!=null && imgViewRef.get()!=null) {
imgViewRef.get().setImageBitmap(image);
} else {
Log.d("Set image", "Dead reference! setting bitmap cancelled");
}
}
});
}
Run Code Online (Sandbox Code Playgroud)
如你所见,我正在尝试使用WeakReference我的ImageViews来设置图像,只有当ImageView还活着并且避免泄漏视图引用时ListView.但是,这似乎不起作用.正常情况下会为前几个可见项加载图像,但是当我开始滚动我的ListView图像时,我会看到不正确的图像(以前的列表项中使用的图像),这很烦人.我怎么能避免这个?下载完成后,图像将被替换为正确的图像,但下载可能需要一段时间.
一个明显的解决方法是隐藏,ImageView直到下载完成,然后显示它,但还有其他方法吗?
编辑:ImageCache类的其他一些方法:
//used to track requests for each image URL, key is URL
private Map<String, Queue<OnImageLoadedListener>> listeners;
//...
public void get(String imageUrl, OnImageLoadedListener listener) {
final String key=this.getKey(imageUrl);
Bitmap image;
Log.d(LOG_TAG, "image "+key+" for "+listener.hashCode()+": requesting...");
if (!listeners.containsKey(key)) {
listeners.put(key, new LinkedList<OnImageLoadedListener>());
}
Queue<OnImageLoadedListener> imageListenersQueue=listeners.get(key);
imageListenersQueue.add(listener);
//check if there are other requests for the same image
if (imageListenersQueue.size()>1) {
Log.d(LOG_TAG, "image "+key+" for "+listener.hashCode()+": already requested...");
return;
}
//proceed only if this request is the first
Log.d(LOG_TAG, "image "+key+" for "+listener.hashCode()+": proceeding...");
image=memCache.get(key);
if (image==null && diskCache!=null) {
image=diskCache.getBitmap(key);
if (image==null) {
new BitmapDownloader(new OnImageLoadedListener() {
public void onImageLoaded(Bitmap image) {
if (image!=null) {
memCache.put(key, image);
diskCache.put(key, image);
}
post(key, image);
Log.d(LOG_TAG, "image "+key+", downloaded bitmap "+image.hashCode());
}
}).execute(imageUrl);
} else {
memCache.put(key, image);
Log.d(LOG_TAG, "image "+key+" found in diskcache");
post(key, image);
}
} else {
Log.d(LOG_TAG, "image "+key+" found in memcache");
post(key, image);
}
}
private void post(String key, Bitmap bitmap) {
//will now pass bitmap to all listeners
LinkedList<OnImageLoadedListener> imageListenersQueue=(LinkedList<OnImageLoadedListener>) listeners.get(key);
while (!imageListenersQueue.isEmpty()) {
imageListenersQueue.remove().onImageLoaded(bitmap);
}
}
//and the mysterious getKey()
private String getKey(String str) {
return Integer.toHexString(str.hashCode());
}
Run Code Online (Sandbox Code Playgroud)
这是ImageCache的日志输出:
第一个可见列表项:
12-05 12:30:06.036: D/ImageCache(21138): image 40bc8de0 for 1104135776: requesting...
12-05 12:30:06.036: D/ImageCache(21138): image 40bc8de0 for 1104135776: proceeding...
12-05 12:30:06.071: D/ImageCache(21138): image 6589e90 for 1103929688: requesting...
12-05 12:30:06.071: D/ImageCache(21138): image 6589e90 for 1103929688: proceeding...
12-05 12:30:07.251: D/ImageCache(21138): image 40bc8de0 for 1104135776 ready, setting bitmap 1104282656
12-05 12:30:07.255: D/ImageCache(21138): image 40bc8de0, downloaded bitmap 1104282656
12-05 12:30:08.407: D/ImageCache(21138): image 6589e90 for 1103929688 ready, setting bitmap 1104663160
12-05 12:30:08.411: D/ImageCache(21138): image 6589e90, downloaded bitmap 1104663160
Run Code Online (Sandbox Code Playgroud)
滚动到下一个项目时:
12-05 12:30:44.669: D/ImageCache(21138): image 2e762e6c for 1104686624: requesting...
12-05 12:30:44.673: D/ImageCache(21138): image 2e762e6c for 1104686624: proceeding...
12-05 12:30:45.997: D/ImageCache(21138): image 2e762e6c for 1104686624 ready, setting bitmap 1104089312
12-05 12:30:45.997: D/ImageCache(21138): image 2e762e6c, downloaded bitmap 1104089312
Run Code Online (Sandbox Code Playgroud)
似乎问题不在缓存机制中,因为load()对此项目的唯一调用为我提供了完全符合请求的正确图像集ImageView.只是在下载和设置之前显示不正确的图像.
这里需要考虑两件事.首先,当您在缓存中找不到目标位图时,应将ImageView源设置为某种加载drawable.这很简单.
其次,您需要将视图回收考虑在内.您的代码中没有任何内容可以阻止您开始下载的场景ImageView,但在onImageLoaded()调用之前,适配器中的View将被回收以显示其他图像.然后,下载完成,导致显示完全错误的图像.
一个典型的解决方案是调用setTag()你的ImageView,并设置它应该加载的URL.在load()方法的开头执行此操作.然后,您可能希望onImageLoaded()为URL 添加额外的参数.检查此URL是否与ImageView标记匹配,仅setImageBitmap()在URL匹配时调用.
| 归档时间: |
|
| 查看次数: |
3260 次 |
| 最近记录: |