Android 异步加载网络图片并缓存到本地

转载自:http://blog.csdn.net/w337198302/article/details/11845017

这篇文章算是现在很多公司当前都在使用的技术,可以好好学习下,我们使用的也差不多,还可以再参照改进下!感谢原文作者~


在android应用开发的时候,加载网络图片是一个非常重要的部分,很多图片不可能放在本地,所以就必须要从服务器或者网络读取图片。

软引用是一个现在非常流行的方法,用户体验比较好,不用每次都需要从网络下载图片,如果下载后就存到本地,下次读取时首先查看本地有没有,如果没有再从网络读取。

记得2月份在和爱奇艺公司的项目总监一起搞联通的OTT盒子的时候他就提了一下软引用,奇艺做的手机客户端就是采用这种方法,所以你会发现奇艺客户端占用很大的空间,下面就分享一下异步加载网络图片的方法吧。


FileCache.java

[java]  view plain copy
  1. import java.io.File;  
  2. import android.content.Context;  
  3.   
  4. public class FileCache {  
  5.   
  6.     private File cacheDir;  
  7.   
  8.     public FileCache(Context context) {  
  9.         // 找一个用来缓存图片的路径  
  10.         if (android.os.Environment.getExternalStorageState().equals(  
  11.                 android.os.Environment.MEDIA_MOUNTED))  
  12.             cacheDir = new File(android.os.Environment.getExternalStorageDirectory(),  
  13.                     "文件夹名称");  
  14.         else  
  15.             cacheDir = context.getCacheDir();  
  16.         if (!cacheDir.exists())  
  17.             cacheDir.mkdirs();  
  18.     }  
  19.   
  20.     public File getFile(String url) {  
  21.         String filename = String.valueOf(url.hashCode());  
  22.         File f = new File(cacheDir, filename);  
  23.         return f;  
  24.     }  
  25.   
  26.     public void clear() {  
  27.         File[] files = cacheDir.listFiles();  
  28.         if (files == null)  
  29.             return;  
  30.         for (File f : files)  
  31.             f.delete();  
  32.     }  
  33.   
  34. }  


HttpUtil.java

[java]  view plain copy
  1. import java.io.ByteArrayOutputStream;  
  2. import java.io.File;  
  3. import java.io.FileNotFoundException;  
  4. import java.io.FileOutputStream;  
  5. import java.io.IOException;  
  6. import java.io.InputStream;  
  7. import java.io.OutputStream;  
  8. import java.io.UnsupportedEncodingException;  
  9. import java.net.HttpURLConnection;  
  10. import java.net.MalformedURLException;  
  11. import java.net.ProtocolException;  
  12. import java.net.URL;  
  13. import java.net.URLEncoder;  
  14. import java.util.Map;  
  15.   
  16. /** 
  17.  * Http 请求工具类 
  18.  *  
  19.  * @author Scorpio.Liu 
  20.  *  
  21.  */  
  22. public class HttpUtil {  
  23.   
  24.     /** 
  25.      * 获取响应字符串 
  26.      *  
  27.      * @param path 
  28.      *            路径 
  29.      * @param parameters 
  30.      *            参数 
  31.      * @return 响应字符串 
  32.      */  
  33.     public static String getResponseStr(String path, Map parameters) {  
  34.         StringBuffer buffer = new StringBuffer();  
  35.         URL url;  
  36.         try {  
  37.             if (parameters != null && !parameters.isEmpty()) {  
  38.                 for (Map.Entry entry : parameters.entrySet()) {  
  39.                     // 完成转码操作  
  40.                     buffer.append(entry.getKey()).append("=")  
  41.                             .append(URLEncoder.encode(entry.getValue(), "UTF-8")).append("&");  
  42.                 }  
  43.                 buffer.deleteCharAt(buffer.length() - 1);  
  44.             }  
  45.             url = new URL(path);  
  46.             HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();  
  47.             urlConnection.setConnectTimeout(3000);  
  48.             urlConnection.setRequestMethod("POST");  
  49.             urlConnection.setDoInput(true);// 表示从服务器获取数据  
  50.             urlConnection.setDoOutput(true);// 表示向服务器写数据  
  51.             // 获得上传信息的字节大小以及长度  
  52.             byte[] mydata = buffer.toString().getBytes();  
  53.             // 表示设置请求体的类型是文本类型  
  54.             urlConnection.setRequestProperty("Content-Type",  
  55.                     "application/x-www-form-urlencoded");  
  56.             urlConnection.setRequestProperty("Content-Length", String.valueOf(mydata.length));  
  57.             // 获得输出流,向服务器输出数据  
  58.             OutputStream outputStream = urlConnection.getOutputStream();  
  59.             outputStream.write(mydata, 0, mydata.length);  
  60.             outputStream.close();  
  61.             int responseCode = urlConnection.getResponseCode();  
  62.             if (responseCode == 200) {  
  63.                 return changeInputStream(urlConnection.getInputStream());  
  64.             }  
  65.         } catch (UnsupportedEncodingException e) {  
  66.             e.printStackTrace();  
  67.         } catch (MalformedURLException e) {  
  68.             e.printStackTrace();  
  69.         } catch (ProtocolException e) {  
  70.             e.printStackTrace();  
  71.         } catch (IOException e) {  
  72.             e.printStackTrace();  
  73.         }  
  74.         return null;  
  75.     }  
  76.   
  77.     private static String changeInputStream(InputStream inputStream) {  
  78.         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();  
  79.         byte[] data = new byte[1024];  
  80.         int len = 0;  
  81.         String result = "";  
  82.         if (inputStream != null) {  
  83.             try {  
  84.                 while ((len = inputStream.read(data)) != -1) {  
  85.                     outputStream.write(data, 0, len);  
  86.                 }  
  87.                 result = new String(outputStream.toByteArray(), "UTF-8");  
  88.             } catch (IOException e) {  
  89.                 e.printStackTrace();  
  90.             }  
  91.         }  
  92.         return result;  
  93.     }  
  94.   
  95.     public static InputStream getInputStream(String path) {  
  96.         URL url;  
  97.         try {  
  98.             url = new URL(path);  
  99.             HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();  
  100.             urlConnection.setConnectTimeout(3000);  
  101.             urlConnection.setRequestMethod("GET");  
  102.             urlConnection.setDoInput(true);// 表示从服务器获取数据  
  103.             urlConnection.connect();  
  104.             if (urlConnection.getResponseCode() == 200)  
  105.                 return urlConnection.getInputStream();  
  106.         } catch (MalformedURLException e) {  
  107.             // TODO Auto-generated catch block  
  108.             e.printStackTrace();  
  109.         } catch (IOException e) {  
  110.             // TODO Auto-generated catch block  
  111.             e.printStackTrace();  
  112.         } catch (Exception e) {  
  113.             // TODO Auto-generated catch block  
  114.             e.printStackTrace();  
  115.         }  
  116.         return null;  
  117.     }  
  118.   
  119.     public static byte[] readStream(InputStream inStream) throws Exception {  
  120.         ByteArrayOutputStream outSteam = new ByteArrayOutputStream();  
  121.         byte[] buffer = new byte[1024];  
  122.         int len = -1;  
  123.         while ((len = inStream.read(buffer)) != -1) {  
  124.             outSteam.write(buffer, 0, len);  
  125.   
  126.         }  
  127.         outSteam.close();  
  128.         inStream.close();  
  129.         return outSteam.toByteArray();  
  130.     }  
  131.   
  132.     public static void CopyStream(String url, File f) {  
  133.         FileOutputStream fileOutputStream = null;  
  134.         InputStream inputStream = null;  
  135.         try {  
  136.             inputStream = getInputStream(url);  
  137.             byte[] data = new byte[1024];  
  138.             int len = 0;  
  139.             fileOutputStream = new FileOutputStream(f);  
  140.             while ((len = inputStream.read(data)) != -1) {  
  141.                 fileOutputStream.write(data, 0, len);  
  142.             }  
  143.         } catch (FileNotFoundException e) {  
  144.             e.printStackTrace();  
  145.         } catch (IOException e) {  
  146.             e.printStackTrace();  
  147.         } finally {  
  148.             if (inputStream != null) {  
  149.                 try {  
  150.                     inputStream.close();  
  151.                 } catch (IOException e) {  
  152.                     e.printStackTrace();  
  153.                 }  
  154.             }  
  155.             if (fileOutputStream != null) {  
  156.                 try {  
  157.                     fileOutputStream.close();  
  158.                 } catch (IOException e) {  
  159.                     e.printStackTrace();  
  160.                 }  
  161.             }  
  162.         }  
  163.     }  
  164.   
  165. }  

MemoryCache.java

[java]  view plain copy
  1. import java.lang.ref.SoftReference;  
  2. import java.util.Collections;  
  3. import java.util.HashMap;  
  4. import java.util.Map;  
  5. import android.graphics.Bitmap;  
  6.   
  7. public class MemoryCache {  
  8.     private Map> cache = Collections  
  9.             .synchronizedMap(new HashMap>());// 软引用  
  10.   
  11.     public Bitmap get(String id) {  
  12.         if (!cache.containsKey(id))  
  13.             return null;  
  14.         SoftReference ref = cache.get(id);  
  15.         return ref.get();  
  16.     }  
  17.   
  18.     public void put(String id, Bitmap bitmap) {  
  19.         cache.put(id, new SoftReference(bitmap));  
  20.     }  
  21.   
  22.     public void clear() {  
  23.         cache.clear();  
  24.     }  
  25. }  

ImageLoader.java

[java]  view plain copy
  1. import java.io.File;  
  2. import java.io.FileInputStream;  
  3. import java.io.FileNotFoundException;  
  4. import java.io.UnsupportedEncodingException;  
  5. import java.net.URLEncoder;  
  6. import java.util.Collections;  
  7. import java.util.Map;  
  8. import java.util.WeakHashMap;  
  9. import java.util.concurrent.ExecutorService;  
  10. import java.util.concurrent.Executors;  
  11. import android.app.Activity;  
  12. import android.content.Context;  
  13. import android.graphics.Bitmap;  
  14. import android.graphics.BitmapFactory;  
  15. import android.graphics.drawable.BitmapDrawable;  
  16. import android.widget.ImageView;  
  17.   
  18. public class ImageLoader {  
  19.   
  20.     private MemoryCache memoryCache = new MemoryCache();  
  21.     private FileCache fileCache;  
  22.     private Map imageViews = Collections  
  23.             .synchronizedMap(new WeakHashMap());  
  24.     private ExecutorService executorService;  
  25.     private boolean isSrc;  
  26.   
  27.     /** 
  28.      * @param context 
  29.      *            上下文对象 
  30.      * @param flag 
  31.      *            true为source资源,false为background资源 
  32.      */  
  33.     public ImageLoader(Context context, boolean flag) {  
  34.         fileCache = new FileCache(context);  
  35.         executorService = Executors.newFixedThreadPool(5);  
  36.         isSrc = flag;  
  37.     }  
  38.   
  39.     final int stub_id = R.drawable.ic_launcher;  
  40.   
  41.     public void DisplayImage(String url, ImageView imageView) {  
  42.         String u1 = url.substring(0, url.lastIndexOf("/") + 1);  
  43.         String u2 = url.substring(url.lastIndexOf("/") + 1);  
  44.         try {  
  45.             u2 = URLEncoder.encode(u2, "UTF-8");  
  46.         } catch (UnsupportedEncodingException e) {  
  47.             e.printStackTrace();  
  48.         }  
  49.         url = u1 + u2;  
  50.         imageViews.put(imageView, url);  
  51.         Bitmap bitmap = memoryCache.get(url);  
  52.         if (bitmap != null) {  
  53.             if (isSrc)  
  54.                 imageView.setImageBitmap(bitmap);  
  55.             else  
  56.                 imageView.setBackgroundDrawable(new BitmapDrawable(bitmap));  
  57.         } else {  
  58.             queuePhoto(url, imageView);  
  59.             if (isSrc)  
  60.                 imageView.setImageResource(stub_id);  
  61.             else  
  62.                 imageView.setBackgroundResource(stub_id);  
  63.         }  
  64.     }  
  65.   
  66.     private void queuePhoto(String url, ImageView imageView) {  
  67.         PhotoToLoad p = new PhotoToLoad(url, imageView);  
  68.         executorService.submit(new PhotosLoader(p));  
  69.     }  
  70.   
  71.     private Bitmap getBitmap(String url) {  
  72.         try {  
  73.             File f = fileCache.getFile(url);  
  74.             // 从sd卡  
  75.             Bitmap b = onDecodeFile(f);  
  76.             if (b != null)  
  77.                 return b;  
  78.             // 从网络  
  79.             Bitmap bitmap = null;  
  80.             System.out.println("ImageLoader-->download");  
  81.             HttpUtil.CopyStream(url, f);  
  82.             bitmap = onDecodeFile(f);  
  83.   
  84.             return bitmap;  
  85.         } catch (Exception ex) {  
  86.             ex.printStackTrace();  
  87.             return null;  
  88.         }  
  89.     }  
  90.   
  91.     public Bitmap onDecodeFile(File f) {  
  92.         try {  
  93.             return BitmapFactory.decodeStream(new FileInputStream(f));  
  94.         } catch (FileNotFoundException e) {  
  95.             // TODO Auto-generated catch block  
  96.             e.printStackTrace();  
  97.         }  
  98.         return null;  
  99.     }  
  100.   
  101.     /** 
  102.      * 解码图像用来减少内存消耗 
  103.      *  
  104.      * @param f 
  105.      * @return 
  106.      */  
  107.     public Bitmap decodeFile(File f) {  
  108.         try {  
  109.             // 解码图像大小  
  110.             BitmapFactory.Options o = new BitmapFactory.Options();  
  111.             o.inJustDecodeBounds = true;  
  112.             BitmapFactory.decodeStream(new FileInputStream(f), null, o);  
  113.             // 找到正确的刻度值,它应该是2的幂。  
  114.             final int REQUIRED_SIZE = 70;  
  115.             int width_tmp = o.outWidth, height_tmp = o.outHeight;  
  116.             int scale = 1;  
  117.             while (true) {  
  118.                 if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE)  
  119.                     break;  
  120.                 width_tmp /= 2;  
  121.                 height_tmp /= 2;  
  122.                 scale *= 2;  
  123.             }  
  124.             BitmapFactory.Options o2 = new BitmapFactory.Options();  
  125.             o2.inSampleSize = scale;  
  126.             return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);  
  127.         } catch (FileNotFoundException e) {  
  128.         }  
  129.         return null;  
  130.     }  
  131.   
  132.     /** 
  133.      * 任务队列 
  134.      *  
  135.      * @author Scorpio.Liu 
  136.      *  
  137.      */  
  138.     private class PhotoToLoad {  
  139.         public String url;  
  140.         public ImageView imageView;  
  141.   
  142.         public PhotoToLoad(String u, ImageView i) {  
  143.             url = u;  
  144.             imageView = i;  
  145.         }  
  146.     }  
  147.   
  148.     class PhotosLoader implements Runnable {  
  149.         PhotoToLoad photoToLoad;  
  150.   
  151.         PhotosLoader(PhotoToLoad photoToLoad) {  
  152.             this.photoToLoad = photoToLoad;  
  153.         }  
  154.   
  155.         @Override  
  156.         public void run() {  
  157.             if (imageViewReused(photoToLoad))  
  158.                 return;  
  159.             Bitmap bmp = getBitmap(photoToLoad.url);  
  160.             memoryCache.put(photoToLoad.url, bmp);  
  161.             if (imageViewReused(photoToLoad))  
  162.                 return;  
  163.             BitmapDisplayer bd = new BitmapDisplayer(bmp, photoToLoad);  
  164.             Activity a = (Activity) photoToLoad.imageView.getContext();  
  165.             a.runOnUiThread(bd);  
  166.         }  
  167.     }  
  168.   
  169.     boolean imageViewReused(PhotoToLoad photoToLoad) {  
  170.         String tag = imageViews.get(photoToLoad.imageView);  
  171.         if (tag == null || !tag.equals(photoToLoad.url))  
  172.             return true;  
  173.         return false;  
  174.     }  
  175.   
  176.     /** 
  177.      * 显示位图在UI线程 
  178.      *  
  179.      * @author Scorpio.Liu 
  180.      *  
  181.      */  
  182.     class BitmapDisplayer implements Runnable {  
  183.         Bitmap bitmap;  
  184.         PhotoToLoad photoToLoad;  
  185.   
  186.         public BitmapDisplayer(Bitmap b, PhotoToLoad p) {  
  187.             bitmap = b;  
  188.             photoToLoad = p;  
  189.         }  
  190.   
  191.         public void run() {  
  192.             if (imageViewReused(photoToLoad))  
  193.                 return;  
  194.             if (bitmap != null) {  
  195.                 if (isSrc)  
  196.                     photoToLoad.imageView.setImageBitmap(bitmap);  
  197.                 else  
  198.                     photoToLoad.imageView.setBackgroundDrawable(new BitmapDrawable(bitmap));  
  199.             } else {  
  200.                 if (isSrc)  
  201.                     photoToLoad.imageView.setImageResource(stub_id);  
  202.                 else  
  203.                     photoToLoad.imageView.setBackgroundResource(stub_id);  
  204.             }  
  205.         }  
  206.     }  
  207.   
  208.     public void clearCache() {  
  209.         memoryCache.clear();  
  210.         fileCache.clear();  
  211.     }  
  212.   
  213. }  

你可能感兴趣的:(Android)