ImageLoader是android开发中常用到的图片缓存技术。本文通过阅读《Android源码设计模式解析与实战》后,了解到一个程序的健壮性,可拓展性是十分重要的。源码设计均来自于《Android源码设计模式解析与实战》: 1.首先定义ImageCache接口,实现图片的缓存和提取两种方法。
public interface ImageCache { void put(String url,Bitmap bitmap); Bitmap get(String url);}复制代码
2.分别实现内存缓存(MemoryCache),sd卡缓存(DiskCache)和双缓存(DoubleCache)策略,其均实现ImageCache接口。
public class MemoryCache implements ImageCache { LruCachemMemoryCache; public MemoryCache(){ initMemoryCache(); } private void initMemoryCache() { //计算可使用的最大内存 final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); //取四分之一的可用内存作为缓存 final int CacheSize = maxMemory / 4; mMemoryCache = new LruCache (CacheSize) { @Override protected int sizeOf(String key, Bitmap value) { //图片的宽高之积/1024(存储的应该是图片的大小) return value.getRowBytes() * value.getHeight() / 1024; } }; } @Override public void put(String url, Bitmap bitmap) { mMemoryCache.put(url,bitmap); } @Override public Bitmap get(String url) { return mMemoryCache.get(url); }}复制代码
public class DiskCache implements ImageCache{ static String cacheDir = "sdcard/cache/"; @Override public void put(String url, Bitmap bitmap) { FileOutputStream fileOutputStream = null; try { fileOutputStream = new FileOutputStream(cacheDir + url); bitmap.compress(Bitmap.CompressFormat.PNG,100,fileOutputStream); } catch (FileNotFoundException e) { e.printStackTrace(); }finally { if(fileOutputStream != null){ try { fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } @Override public Bitmap get(String url) { return BitmapFactory.decodeFile(cacheDir + url); }}复制代码
public class DoubleCache implements ImageCache{ ImageCache mMemmoryCache = new MemoryCache(); ImageCache mDiskCache = new DiskCache(); @Override public void put(String url, Bitmap bitmap) { mMemmoryCache.put(url,bitmap); mDiskCache.put(url,bitmap); } @Override public Bitmap get(String url) { Bitmap bitmap = mMemmoryCache.get(url); if(bitmap == null){ bitmap = mDiskCache.get(url); } return bitmap; }}复制代码
3.创建ImageLoader类
public class ImageLoader { //内存缓存 ImageCache mImageCache = new MemoryCache(); //线程池,线程数量为CPU的数量 ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); public void setImageCache(ImageCache cache){ mImageCache = cache; } public void displayImage(final String url, final ImageView imageView) { //判断该url的图片是否在缓存中存在,存在则直接显示在imageview上 Bitmap bitmap = mImageCache.get(url); if(bitmap != null){ imageView.setImageBitmap(bitmap); return; } //图片没缓存,在线程池中下载 submitLoadRequest(url,imageView); } private void submitLoadRequest(final String url, final ImageView imageView) { imageView.setTag(url); mExecutorService.submit(new Runnable() { @Override public void run() { Bitmap bitmap = downloadImage(url); if (bitmap == null) { return; } if (imageView.getTag().equals(url)) { imageView.setImageBitmap(bitmap); } mImageCache.put(url, bitmap); } }); } private Bitmap downloadImage(String imageurl) { Bitmap bitmap = null; try { URL url = new URL(imageurl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); bitmap = BitmapFactory.decodeStream(conn.getInputStream()); conn.disconnect(); } catch (IOException e) { e.printStackTrace(); } return bitmap; }复制代码
在ImageLoader类中添加setImageCache()方法,用户可以通过此方法决定缓存的方式为以上3种的哪一种。
4.在Activity上进行声明,使用。
public class MainActivity extends AppCompatActivity { private ImageView imageView; private ImageLoader imageLoader; private String url = "http://bmob-cdn-11151.b0.upaiyun.com/2017/06/04/3cdfbcc8400de13c8027b5513d469637.jpg"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private void initView() { imageView = (ImageView)findViewById(R.id.imageView); imageLoader = new ImageLoader(); //使用内存缓存 imageLoader.setImageCache(new MemoryCache()); //使用sd卡缓存 imageLoader.setImageCache(new DiskCache()); //使用doubleCache缓存 imageLoader.setImageCache(new DoubleCache()); //使用自定义的方法缓存 imageLoader.setImageCache(new ImageCache() { @Override public void put(String url, Bitmap bitmap) { } @Override public Bitmap get(String url) { return null; } }); imageLoader.displayImage(url,imageView); }}复制代码
本方法高度内聚,低耦合,在使用过程中,分别使用3中不同的缓存策略,使复杂的代码进行分离,在出现问题时,便于方便的修改,不会影响到其他的代码功能,实现抽象接口的方法还允许开发者使用自定义的缓存策略,可拓展性高。
理解这种程序设计时十分必要的,在以后的开发中要时刻考虑自己程序的健壮性,可拓展性,高内聚低耦合。