Android 异步加载网络图片并缓存到本地 软引用 学习分享

http://software.intel.com/zh-cn/blogs/2014/02/20/android/?utm_campaign=CSDN&utm_source=intel.csdn.net&utm_medium=Link&utm_content=others-ruanyinyong

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

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

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

FileCache.java

  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.  

HttpUtil.java

  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<String, String> parameters) { 
  34.         StringBuffer buffer = new StringBuffer(); 
  35.         URL url; 
  36.         try { 
  37.             if (parameters != null && !parameters.isEmpty()) { 
  38.                 for (Map.Entry<String, String> 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 = newbyte[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 = newbyte[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.  


MemoryCache.java

  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<String, SoftReference<Bitmap>> cache = Collections 
  9.             .synchronizedMap(new HashMap<String, SoftReference<Bitmap>>());// 软引用 
  10.  
  11.     public Bitmap get(String id) { 
  12.         if (!cache.containsKey(id)) 
  13.             return null; 
  14.         SoftReference<Bitmap> 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>(bitmap)); 
  20.     } 
  21.  
  22.     public void clear() { 
  23.         cache.clear(); 
  24.     } 


ImageLoader.java

  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<ImageView, String> imageViews = Collections 
  23.             .synchronizedMap(new WeakHashMap<ImageView, String>()); 
  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.  


使用的时候用ImageLoader这个类就ok了,很方便~

如需更全面地了解编译器优化,请参阅 优化注意事项
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值