Android开发点点滴滴——软摘引缓存图片和异步加载
Android开发点点滴滴——软引用缓存图片和异步加载
1.软引用
Java中的SoftReference即对象的软引用。如果一个对象具有软引用,内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。使用软引用能防止内存泄露,增强程序的健壮性。
SoftReference的特点是它的一个实例保存对一个Java对象的软引用,该软引用的存在不妨碍垃圾收集线程对该Java对象的回收。也就是说,一旦SoftReference保存了对一个Java对象的软引用后,在垃圾线程对这个Java对象回收前,SoftReference类所提供的get()方法返回Java对象的强引用。另外,一旦垃圾线程回收该Java对象之后,get()方法将返回null。
public HashMap<String,SoftReference<Bitmap>> imageCache=new HashMap<String,SoftReference<Bitmap>>();
SoftReference<Bitmap> bmpr=getBitmap(resStr);//从hashmap中通过resStr得到软引用 if(bmpr!=null) { if(bmpr.get()!=null) { return bmpr.get(); } else { bmpr=readBitmapSoftReference(res);//如果内存被回收,bmpr get得到的null,此时,重新得到bitmap的软引用 new SoftReference<Bitmap>(bitmap); if(bmpr!=null) { addBitmap(resStr,bmpr);//添加到hashmap中 return bmpr.get(); } } } else { //应先remove hashmap中的值 bmpr=readBitmapSoftReference(res); if(bmpr!=null) { addBitmap(resStr,bmpr); return bmpr.get(); } }2.图片异步加载
这个问题涉及到线程 软引用等
首先当一个程序要显示网络图片时,下载的过程应该是在另外的线程中,那么就需要在其他线程中通知主线程来改变图片的view
其次,为了速度更快网络资源消耗小,使用缓存图片的方式,当第一次下载后,将图片存在本地,以后再查看时不用在网上重新下载
最后,为了防止内存泄露,使用软引用
图片异步加载类,如下
public class AsyncImageLoader { public HashMap<String,SoftReference<Bitmap>> imageCache=null; public AsyncImageLoader() { imageCache = new HashMap<String,SoftReference<Bitmap>>(); } //先查看缓存中,然后看sd卡 public Bitmap loadBitmap(final ImageView imageView, final String imageURL,final String localImgFullName, final ImageCallBack imageCallBack) { //在内存缓存中,则返回Bitmap对象 if(imageCache.containsKey(imageURL)) { SoftReference<Bitmap> reference = imageCache.get(imageURL); Bitmap bitmap = reference.get(); if(bitmap != null) { return bitmap; } } else { File fis = new File(localImgFullName); if(!fis.exists()) return null; return new SoftReference<Bitmap>(BitmapFactory.decodeFile(localImgFullName); } final Handler handler = new Handler() { @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub imageCallBack.imageLoad(imageView, (Bitmap)msg.obj); } }; //如果不在内存缓存中,也不在本地(被jvm回收掉),则开启线程下载图片 new Thread() { @Override public void run() { // TODO Auto-generated method stub URL myUrl; InputStream i = null; Bitmap bitmap=null; try{ myUrl = new URL(url); if(myUrl==null) return null; URLConnection myconn=myUrl.openConnection(); i=myconn.getInputStream(); bitmap =BitmapFactory.decodeStream(i); i.close(); if(bmp==null) return null; } catch(Exception e) { e.printStackTrace(); return null; } imageCache.put(imageURL, new SoftReference<Bitmap>(bitmap)); Message msg = handler.obtainMessage(0, bitmap); handler.sendMessage(msg); File bitmapFile = new File(localImgFullName); if(!bitmapFile.exists()) { try { bitmapFile.createNewFile(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } FileOutputStream fos; try { fos = new FileOutputStream(bitmapFile); bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); fos.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }.start(); return null; } public interface ImageCallBack { public void imageLoad(ImageView imageView, Bitmap bitmap); } } }
注意的是在使用的时候,要实现imageCallBack借口
比如在某个地方要使用异步加载图片
AsyncImageLoader asyncBitmapLoader=new AsyncBitmapLoader(); Bitmap bitmap=asyncBitmapLoader.loadBitmap(image, imageURL,imgPath, new ImageCallBack() { @Override public void imageLoad(ImageView imageView, Bitmap bitmap) { // TODO Auto-generated method stub imageView.setImageBitmap(bitmap); } });