异步下载网络图片,并提供是否缓存至内存或外部文件的功能
异步加载类AsyncImageLoader
public void downloadImage(final String url, final ImageCallback callback);
public void downloadImage(final String url, final boolean cache2Memory, final ImageCallback callback);
public void setCache2File(boolean flag);
public void setCachedDir(String dir);
图片下载和缓存实现类LoaderImpl
1.AsyncImageLoader.java
1 package com.imagecache; 2 3 import java.lang.ref.SoftReference; 4 import java.util.HashMap; 5 import java.util.HashSet; 6 import java.util.Map; 7 import java.util.concurrent.ExecutorService; 8 import java.util.concurrent.Executors; 9 10 import android.content.Context; 11 import android.graphics.Bitmap; 12 import android.os.Handler; 13 import android.util.Log; 14 15 public class AsyncImageLoader { 16 //保存正在下载的图片URL集合,避免重复下载用 17 private static HashSet<String> sDownloadingSet; 18 //软引用内存缓存 19 private static Map<String,SoftReference<Bitmap>> sImageCache; 20 //图片三种获取方式管理者,网络URL获取、内存缓存获取、外部文件缓存获取 21 private static LoaderImpl impl; 22 //线程池相关 23 private static ExecutorService sExecutorService; 24 25 //通知UI线程图片获取ok时使用 26 private Handler handler; 27 28 29 /** 30 * 异步加载图片完毕的回调接口 31 */ 32 public interface ImageCallback{ 33 /** 34 * 回调函数 35 * @param bitmap: may be null! 36 * @param imageUrl 37 */ 38 public void onImageLoaded(Bitmap bitmap, String imageUrl); 39 } 40 41 static{ 42 sDownloadingSet = new HashSet<String>(); 43 sImageCache = new HashMap<String,SoftReference<Bitmap>>(); 44 impl = new LoaderImpl(sImageCache); 45 } 46 47 public AsyncImageLoader(Context context){ 48 handler = new Handler(); 49 startThreadPoolIfNecessary(); 50 51 String defaultDir = context.getCacheDir().getAbsolutePath(); 52 setCachedDir(defaultDir); 53 } 54 55 /** 56 * 是否缓存图片至/data/data/package/cache/目录 57 * 默认不缓存 58 */ 59 public void setCache2File(boolean flag){ 60 impl.setCache2File(flag); 61 } 62 63 /** 64 * 设置缓存路径,setCache2File(true)时有效 65 */ 66 public void setCachedDir(String dir){ 67 impl.setCachedDir(dir); 68 } 69 70 /**开启线程池*/ 71 public static void startThreadPoolIfNecessary(){ 72 if(sExecutorService == null || sExecutorService.isShutdown() || sExecutorService.isTerminated()){ 73 sExecutorService = Executors.newFixedThreadPool(3); 74 //sExecutorService = Executors.newSingleThreadExecutor(); 75 } 76 } 77 78 /** 79 * 异步下载图片,并缓存到memory中 80 * @param url 81 * @param callback see ImageCallback interface 82 */ 83 public void downloadImage(final String url, final ImageCallback callback){ 84 downloadImage(url, true, callback); 85 } 86 87 /** 88 * 89 * @param url 90 * @param cache2Memory 是否缓存至memory中 91 * @param callback 92 */ 93 public void downloadImage(final String url, final boolean cache2Memory, final ImageCallback callback){ 94 if(sDownloadingSet.contains(url)){ 95 Log.i("AsyncImageLoader", "###该图片正在下载,不能重复下载!"); 96 return; 97 } 98 99 Bitmap bitmap = impl.getBitmapFromMemory(url); 100 if(bitmap != null){ 101 if(callback != null){ 102 callback.onImageLoaded(bitmap, url); 103 } 104 }else{ 105 //从网络端下载图片 106 sDownloadingSet.add(url); 107 sExecutorService.submit(new Runnable(){ 108 @Override 109 public void run() { 110 final Bitmap bitmap = impl.getBitmapFromUrl(url, cache2Memory); 111 handler.post(new Runnable(){ 112 @Override 113 public void run(){ 114 if(callback != null) 115 callback.onImageLoaded(bitmap, url); 116 sDownloadingSet.remove(url); 117 } 118 }); 119 } 120 }); 121 } 122 } 123 124 /** 125 * 预加载下一张图片,缓存至memory中 126 * @param url 127 */ 128 public void preLoadNextImage(final String url){ 129 //将callback置为空,只将bitmap缓存到memory即可。 130 downloadImage(url, null); 131 } 132 133 }
2.LoaderImpl.java
1 package com.imagecache; 2 3 import java.io.FileInputStream; 4 import java.io.FileNotFoundException; 5 import java.io.FileOutputStream; 6 import java.io.IOException; 7 import java.io.InputStream; 8 import java.io.UnsupportedEncodingException; 9 import java.lang.ref.SoftReference; 10 import java.net.HttpURLConnection; 11 import java.net.URL; 12 import java.security.MessageDigest; 13 import java.security.NoSuchAlgorithmException; 14 import java.util.Map; 15 16 import android.graphics.Bitmap; 17 import android.graphics.BitmapFactory; 18 19 /** 20 * 21 * @author Administrator 22 * @desc 异步加载图片管理器 23 * 24 */ 25 public class LoaderImpl { 26 //内存中的软应用缓存 27 private Map<String, SoftReference<Bitmap>> imageCache; 28 29 //是否缓存图片至本地文件 30 private boolean cache2FileFlag = false; 31 32 //缓存目录,默认是/data/data/package/cache/目录 33 private String cachedDir; 34 35 public LoaderImpl(Map<String, SoftReference<Bitmap>> imageCache){ 36 this.imageCache = imageCache; 37 } 38 39 /** 40 * 是否缓存图片至外部文件 41 * @param flag 42 */ 43 public void setCache2File(boolean flag){ 44 cache2FileFlag = flag; 45 } 46 47 /** 48 * 设置缓存图片到外部文件的路径 49 * @param cacheDir 50 */ 51 public void setCachedDir(String cacheDir){ 52 this.cachedDir = cacheDir; 53 } 54 55 /** 56 * 从网络端下载图片 57 * @param url 网络图片的URL地址 58 * @param cache2Memory 是否缓存(缓存在内存中) 59 * @return bitmap 图片bitmap结构 60 * 61 */ 62 public Bitmap getBitmapFromUrl(String url, boolean cache2Memory){ 63 Bitmap bitmap = null; 64 try{ 65 URL u = new URL(url); 66 HttpURLConnection conn = (HttpURLConnection)u.openConnection(); 67 InputStream is = conn.getInputStream(); 68 bitmap = BitmapFactory.decodeStream(is); 69 70 if(cache2Memory){ 71 //1.缓存bitmap至内存软引用中 72 imageCache.put(url, new SoftReference<Bitmap>(bitmap)); 73 if(cache2FileFlag){ 74 //2.缓存bitmap至/data/data/packageName/cache/文件夹中 75 String fileName = getMD5Str(url); 76 String filePath = this.cachedDir + "/" +fileName; 77 FileOutputStream fos = new FileOutputStream(filePath); 78 bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); 79 } 80 } 81 82 is.close(); 83 conn.disconnect(); 84 return bitmap; 85 }catch(IOException e){ 86 e.printStackTrace(); 87 return null; 88 } 89 } 90 91 /** 92 * 从内存缓存中获取bitmap 93 * @param url 94 * @return bitmap or null. 95 */ 96 public Bitmap getBitmapFromMemory(String url){ 97 Bitmap bitmap = null; 98 if(imageCache.containsKey(url)){ 99 synchronized(imageCache){ 100 SoftReference<Bitmap> bitmapRef = imageCache.get(url); 101 if(bitmapRef != null){ 102 bitmap = bitmapRef.get(); 103 return bitmap; 104 } 105 } 106 } 107 //从外部缓存文件读取 108 if(cache2FileFlag){ 109 bitmap = getBitmapFromFile(url); 110 if(bitmap != null) 111 imageCache.put(url, new SoftReference<Bitmap>(bitmap)); 112 } 113 114 return bitmap; 115 } 116 117 /** 118 * 从外部文件缓存中获取bitmap 119 * @param url 120 * @return 121 */ 122 private Bitmap getBitmapFromFile(String url){ 123 Bitmap bitmap = null; 124 String fileName = getMD5Str(url); 125 if(fileName == null) 126 return null; 127 128 String filePath = cachedDir + "/" + fileName; 129 130 try { 131 FileInputStream fis = new FileInputStream(filePath); 132 bitmap = BitmapFactory.decodeStream(fis); 133 } catch (FileNotFoundException e) { 134 e.printStackTrace(); 135 bitmap = null; 136 } 137 return bitmap; 138 } 139 140 141 /** 142 * MD5 加密 143 */ 144 private static String getMD5Str(String str) { 145 MessageDigest messageDigest = null; 146 try { 147 messageDigest = MessageDigest.getInstance("MD5"); 148 messageDigest.reset(); 149 messageDigest.update(str.getBytes("UTF-8")); 150 } catch (NoSuchAlgorithmException e) { 151 System.out.println("NoSuchAlgorithmException caught!"); 152 return null; 153 } catch (UnsupportedEncodingException e) { 154 e.printStackTrace(); 155 return null; 156 } 157 158 byte[] byteArray = messageDigest.digest(); 159 StringBuffer md5StrBuff = new StringBuffer(); 160 for (int i = 0; i < byteArray.length; i++) { 161 if (Integer.toHexString(0xFF & byteArray[i]).length() == 1) 162 md5StrBuff.append("0").append(Integer.toHexString(0xFF & byteArray[i])); 163 else 164 md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i])); 165 } 166 167 return md5StrBuff.toString(); 168 } 169 170 /** 171 * MD5 加密 172 private static String getMD5Str(Object...objects){ 173 StringBuilder stringBuilder=new StringBuilder(); 174 for (Object object : objects) { 175 stringBuilder.append(object.toString()); 176 } 177 return getMD5Str(stringBuilder.toString()); 178 }*/ 179 }
3.测试Activity
1 package com.imagecache; 2 3 import android.app.Activity; 4 import android.graphics.Bitmap; 5 import android.os.Bundle; 6 import android.widget.ImageView; 7 8 public class MainActivity extends Activity { 9 /** Called when the activity is first created. */ 10 @Override 11 public void onCreate(Bundle savedInstanceState) { 12 super.onCreate(savedInstanceState); 13 setContentView(R.layout.main); 14 15 final ImageView iv = (ImageView)findViewById(R.id.iv); 16 //网络图片地址 17 String imgUrl = "http://..."; 18 19 //for test 20 AsyncImageLoader loader = new AsyncImageLoader(getApplicationContext()); 21 22 //将图片缓存至外部文件中 23 loader.setCache2File(true); //false 24 //设置外部缓存文件夹 25 loader.setCachedDir(this.getCacheDir().getAbsolutePath()); 26 27 //下载图片,第二个参数是否缓存至内存中 28 loader.downloadImage(imgUrl, true/*false*/, new AsyncImageLoader.ImageCallback() { 29 @Override 30 public void onImageLoaded(Bitmap bitmap, String imageUrl) { 31 if(bitmap != null){ 32 iv.setImageBitmap(bitmap); 33 }else{ 34 //下载失败,设置默认图片 35 } 36 } 37 }); 38 } 39 40 }