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 }
复制代码


更多相关文章

  1. Android之动画(Java代码实现)1
  2. Android如何拍照或选择图片并裁剪
  3. 【第一行代码】Android日志工具
  4. Android加载图片时OOM异常解决办法——Bitmap Options
  5. Android 本地代码中的LIKELY和UNLIKELY宏
  6. Android 截取屏幕图片并保存
  7. Cocos2dx android 部分代码的理解
  8. 【Android】内嵌html页面与native代码简单交互

随机推荐

  1. Android(安卓)采用Pull解析XML内容 【学
  2. Android(安卓)仿微信支付密码界面
  3. android图层划分(PhoneWindowManager.win
  4. android——Bitmap.Config ARGB_8888
  5. Android(安卓)ImageSwitcher
  6. 使Android支持Lambda表达式
  7. Android(安卓)之 ProgressBar用法介绍
  8. android jni
  9. Android(安卓)OEM 厂商提供的 USB驱动
  10. Android(安卓)仿苹果底部弹出Dialog