Android 图片异步加载的体会,SoftReference已经不再适用

来源:互联网 发布:f16 性能数据 编辑:程序博客网 时间:2024/05/17 21:52

Android 图片异步加载的体会,SoftReference已经不再适用

在网络上搜索Android图片异步加载的相关文章,目前大部分提到的解决方案,都是采用Map<String, SoftReference<Drawable>>  这样软引用的方式缓存网络图片。具体的例子见这篇文章

核心代码如下:
复制代码
 1 public class AsyncImageLoader { 2  3      private HashMap<String, SoftReference<Drawable>> imageCache; 4        5          public AsyncImageLoader() { 6              imageCache = new HashMap<String, SoftReference<Drawable>>(); 7          } 8        9          public Drawable loadDrawable(final String imageUrl, final ImageCallback imageCallback) {10              if (imageCache.containsKey(imageUrl)) {11                  SoftReference<Drawable> softReference = imageCache.get(imageUrl);12                  Drawable drawable = softReference.get();13                  if (drawable != null) {14                      return drawable;15                  }16              }17              final Handler handler = new Handler() {18                  public void handleMessage(Message message) {19                      imageCallback.imageLoaded((Drawable) message.obj, imageUrl);20                  }21              };22              new Thread() {23                  @Override24                  public void run() {25                      Drawable drawable = loadImageFromUrl(imageUrl);26                      imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));27                      Message message = handler.obtainMessage(0, drawable);28                      handler.sendMessage(message);29                  }30              }.start();31              return null;32          }33       34         public static Drawable loadImageFromUrl(String url) {35             URL m;36             InputStream i = null;37             try {38                 m = new URL(url);39                 i = (InputStream) m.getContent();40             } catch (MalformedURLException e1) {41                 e1.printStackTrace();42             } catch (IOException e) {43                 e.printStackTrace();44             }45             Drawable d = Drawable.createFromStream(i, "src");46             return d;47         }48       49          public interface ImageCallback {50              public void imageLoaded(Drawable imageDrawable, String imageUrl);51          }52 53 }
复制代码


最开始时我在自己的项目中也采取这样的代码段,从界面上来说没有发现什么问题,也还算流畅。可后来某次抓包分析数据的时候,在ListView异步加载图片已经完全,我在上下滑动listview时,依旧会有网络请求发出不断加载图片,非常奇怪。从以上代码里可以看到,异步加载下来的图片全都存在了imageCache中,应该可以直接调用缓存中的图片来显示就可以了。

查找资料以后发现了其中的玄机,具体可见Android官方的这篇文章,Caching Bitmaps。里面提到用 SoftReference 或者 WeakReference做图片缓存的方法在Android 2.3版本以后已经不被推荐了。因为内存对SoftReference和WeakReference的回收更加频繁,从而也导致了我在上面说的反复从网络上拉取图片的操作。

Android官方推荐最新的解决办法,是采用LruCache。如果图片数量巨大,也可以进一步考虑将图片缓存到sd卡中,可以采用DiskLruCache。具体的逻辑和上文其实差不多。相关代码如下:

复制代码
 1 private LruCache<String, Bitmap> mMemoryCache; 2  3 @Override 4 protected void onCreate(Bundle savedInstanceState) { 5     ... 6     // Get max available VM memory, exceeding this amount will throw an 7     // OutOfMemory exception. Stored in kilobytes as LruCache takes an 8     // int in its constructor. 9     final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);10 11     // Use 1/8th of the available memory for this memory cache.12     final int cacheSize = maxMemory / 8;13 14     mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {15         @Override16         protected int sizeOf(String key, Bitmap bitmap) {17             // The cache size will be measured in kilobytes rather than18             // number of items.19             return bitmap.getByteCount() / 1024;20         }21     };22     ...23 }24 25 public void addBitmapToMemoryCache(String key, Bitmap bitmap) {26     if (getBitmapFromMemCache(key) == null) {27         mMemoryCache.put(key, bitmap);28     }29 }30 31 public Bitmap getBitmapFromMemCache(String key) {32     return mMemoryCache.get(key);33 }
复制代码

 


0 0
原创粉丝点击