我有一个列表视图,可能会在无限滚动时加载无限数量的项。
列表视图中的每个项都有一到两张图片,我正在使用懒加载技术进行加载。
一切正常,但当我长时间滚动列表视图时,日志窗口中出现以下错误导致应用程序崩溃:
08-07 15:26:25.231: E/AndroidRuntime(30979): FATAL EXCEPTION: Thread-60
08-07 15:26:25.231: E/AndroidRuntime(30979): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
08-07 15:26:25.231: E/AndroidRuntime(30979): at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
08-07 15:26:25.231: E/AndroidRuntime(30979): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:493)
08-07 15:26:25.231: E/AndroidRuntime(30979): at com.test.android.helper.LazyImageLoader.decodeFile(LazyImageLoader.java:171)
08-07 15:26:25.231: E/AndroidRuntime(30979): at com.test.android.helper.LazyImageLoader.getBitmap(LazyImageLoader.java:112)
08-07 15:26:25.231: E/AndroidRuntime(30979): at com.test.android.helper.LazyImageLoader.access$2(LazyImageLoader.java:106)
08-07 15:26:25.231: E/AndroidRuntime(30979): at com.test.android.helper.LazyImageLoader$ImageLoader.run(LazyImageLoader.java:197)
在我的懒惰图片加载器中,我将位图存储在
WeakHashMap
中。因此,垃圾收集器应该会收集位图,对吗?我的懒惰图片加载器的工作方式如下:
我从适配器中使用url和imageview的引用调用
displayImage()
。public void displayImage(String url, ImageView imageView, int defaultImageResourceId){
latestImageMetaData.put(imageView, url);
if(weakhashmapcache.containsKey(url)){
imageView.setImageBitmap(weakhashmapcache.get(url));
}
else{
enqueueImage(url, imageView, defaultImageResourceId);
imageView.setImageResource(defaultImageResourceId);
}
}
如果我在缓存中找到了这张图片,我会直接设置它。否则,我会使用函数enqueueImage()
将其排队。
private void enqueueImage(String url, ImageView imageView, int defaultImageResourceId){ Image image = new Image(url, imageView, defaultImageResourceId); downloadqueue.add(image); // downloadQueue是一个阻塞队列,它等待添加图像 // 如果队列即将满,则删除队列中前面的元素,因为它们无论如何都不可见 Iterator iterator = downloadQueue.iterator(); while(iterator.hasNext() && downloadQueue.remainingCapacity() < 80){ downloadQueue.remove(iterator.next()); } }
And my image loader thread is this -
class ImageLoader extends Thread {
public void run() {
Image firstImageInQueue;
try {
while((firstImageInQueue = downloadQueue.take()) != SHUTDOWN_TOKEN)
{
Bitmap imageBitmap = getBitmap(firstImageInQueue.url);
if(imageBitmap != null){
weakhashmap.put(firstImageInQueue.url, imageBitmap);
BitmapDisplayer displayer = new BitmapDisplayer(imageBitmap, firstImageInQueue.imageView, firstImageInQueue.url, firstImageInQueue.defaultImageResourceId);
Activity activity = (Activity)firstImageInQueue.imageView.getContext();
activity.runOnUiThread(displayer);
}
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
finally {
imageLoaderTerminated = true;
}
}
}
getBitmap()
方法仅从URL获取图像并将其缩放解码为位图对象。 BitmapDisplayer
是一个在UI线程上设置图像到ImageView的Runnable。
您是否有什么做错了?
BitmapFactory.Options
将它们缩小可能是值得的。 - Alex Curran