首页 > 代码库 > Android 异步加载网络图片并缓存到本地

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

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

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

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

FileCache.java

import java.io.File;  import android.content.Context;   public class FileCache {      private File cacheDir;      public FileCache(Context context) {         // 找一个用来缓存图片的路径         if (android.os.Environment.getExternalStorageState().equals(                 android.os.Environment.MEDIA_MOUNTED))             cacheDir = new File(android.os.Environment.getExternalStorageDirectory(),                     "文件夹名称");         else             cacheDir = context.getCacheDir();         if (!cacheDir.exists())             cacheDir.mkdirs();     }      public File getFile(String url) {         String filename = String.valueOf(url.hashCode());         File f = new File(cacheDir, filename);         return f;     }      public void clear() {         File[] files = cacheDir.listFiles();         if (files == null)             return;         for (File f : files)             f.delete();     }   }

HttpUtil.java

import java.io.ByteArrayOutputStream;  import java.io.File;  import java.io.FileNotFoundException;  import java.io.FileOutputStream;  import java.io.IOException;  import java.io.InputStream;  import java.io.OutputStream;  import java.io.UnsupportedEncodingException;  import java.net.HttpURLConnection;  import java.net.MalformedURLException;  import java.net.ProtocolException;  import java.net.URL;  import java.net.URLEncoder;  import java.util.Map;   /*** Http 请求工具类*  * @author Scorpio.Liu*  */  public class HttpUtil {      /**    * 获取响应字符串    *      * @param path    *            路径    * @param parameters    *            参数    * @return 响应字符串    */     public static String getResponseStr(String path, Map<String, String> parameters) {         StringBuffer buffer = new StringBuffer();         URL url;         try {             if (parameters != null && !parameters.isEmpty()) {                 for (Map.Entry<String, String> entry : parameters.entrySet()) {                     // 完成转码操作                     buffer.append(entry.getKey()).append("=")                             .append(URLEncoder.encode(entry.getValue(), "UTF-8")).append("&");                 }                 buffer.deleteCharAt(buffer.length() - 1);             }             url = new URL(path);             HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();             urlConnection.setConnectTimeout(3000);             urlConnection.setRequestMethod("POST");             urlConnection.setDoInput(true);// 表示从服务器获取数据             urlConnection.setDoOutput(true);// 表示向服务器写数据             // 获得上传信息的字节大小以及长度             byte[] mydata =http://www.mamicode.com/ buffer.toString().getBytes();             // 表示设置请求体的类型是文本类型             urlConnection.setRequestProperty("Content-Type",                     "application/x-www-form-urlencoded");             urlConnection.setRequestProperty("Content-Length", String.valueOf(mydata.length));             // 获得输出流,向服务器输出数据             OutputStream outputStream = urlConnection.getOutputStream();             outputStream.write(mydata, 0, mydata.length);             outputStream.close();             int responseCode = urlConnection.getResponseCode();             if (responseCode == 200) {                 return changeInputStream(urlConnection.getInputStream());             }         } catch (UnsupportedEncodingException e) {             e.printStackTrace();         } catch (MalformedURLException e) {             e.printStackTrace();         } catch (ProtocolException e) {             e.printStackTrace();         } catch (IOException e) {             e.printStackTrace();         }         return null;     }      private static String changeInputStream(InputStream inputStream) {         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();         byte[] data = http://www.mamicode.com/new byte[1024];         int len = 0;         String result = "";         if (inputStream != null) {             try {                 while ((len = inputStream.read(data)) != -1) {                     outputStream.write(data, 0, len);                 }                 result = new String(outputStream.toByteArray(), "UTF-8");             } catch (IOException e) {                 e.printStackTrace();             }         }         return result;     }      public static InputStream getInputStream(String path) {         URL url;         try {             url = new URL(path);             HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();             urlConnection.setConnectTimeout(3000);             urlConnection.setRequestMethod("GET");             urlConnection.setDoInput(true);// 表示从服务器获取数据             urlConnection.connect();             if (urlConnection.getResponseCode() == 200)                 return urlConnection.getInputStream();         } catch (MalformedURLException e) {             // TODO Auto-generated catch block             e.printStackTrace();         } catch (IOException e) {             // TODO Auto-generated catch block             e.printStackTrace();         } catch (Exception e) {             // TODO Auto-generated catch block             e.printStackTrace();         }         return null;     }      public static byte[] readStream(InputStream inStream) throws Exception {         ByteArrayOutputStream outSteam = new ByteArrayOutputStream();         byte[] buffer = new byte[1024];         int len = -1;         while ((len = inStream.read(buffer)) != -1) {             outSteam.write(buffer, 0, len);          }         outSteam.close();         inStream.close();         return outSteam.toByteArray();     }      public static void CopyStream(String url, File f) {         FileOutputStream fileOutputStream = null;         InputStream inputStream = null;         try {             inputStream = getInputStream(url);             byte[] data = http://www.mamicode.com/new byte[1024];             int len = 0;             fileOutputStream = new FileOutputStream(f);             while ((len = inputStream.read(data)) != -1) {                 fileOutputStream.write(data, 0, len);             }         } catch (FileNotFoundException e) {             e.printStackTrace();         } catch (IOException e) {             e.printStackTrace();         } finally {             if (inputStream != null) {                 try {                     inputStream.close();                 } catch (IOException e) {                     e.printStackTrace();                 }             }             if (fileOutputStream != null) {                 try {                     fileOutputStream.close();                 } catch (IOException e) {                     e.printStackTrace();                 }             }         }     }   }  

MemoryCache.java

import java.lang.ref.SoftReference;  import java.util.Collections;  import java.util.HashMap;  import java.util.Map;  import android.graphics.Bitmap;   public class MemoryCache {     private Map<String, SoftReference<Bitmap>> cache = Collections             .synchronizedMap(new HashMap<String, SoftReference<Bitmap>>());// 软引用      public Bitmap get(String id) {         if (!cache.containsKey(id))             return null;         SoftReference<Bitmap> ref = cache.get(id);         return ref.get();     }      public void put(String id, Bitmap bitmap) {         cache.put(id, new SoftReference<Bitmap>(bitmap));     }      public void clear() {         cache.clear();     }  }

ImageLoader.java

import java.io.File;  import java.io.FileInputStream;  import java.io.FileNotFoundException;  import java.io.UnsupportedEncodingException;  import java.net.URLEncoder;  import java.util.Collections;  import java.util.Map;  import java.util.WeakHashMap;  import java.util.concurrent.ExecutorService;  import java.util.concurrent.Executors;  import android.app.Activity;  import android.content.Context;  import android.graphics.Bitmap;  import android.graphics.BitmapFactory;  import android.graphics.drawable.BitmapDrawable;  import android.widget.ImageView;   public class ImageLoader {      private MemoryCache memoryCache = new MemoryCache();     private FileCache fileCache;     private Map<ImageView, String> imageViews = Collections             .synchronizedMap(new WeakHashMap<ImageView, String>());     private ExecutorService executorService;     private boolean isSrc;      /**    * @param context    *            上下文对象    * @param flag    *            true为source资源,false为background资源    */     public ImageLoader(Context context, boolean flag) {         fileCache = new FileCache(context);         executorService = Executors.newFixedThreadPool(5);         isSrc = flag;     }      final int stub_id = R.drawable.ic_launcher;      public void DisplayImage(String url, ImageView imageView) {         String u1 = url.substring(0, url.lastIndexOf("/") + 1);         String u2 = url.substring(url.lastIndexOf("/") + 1);         try {             u2 = URLEncoder.encode(u2, "UTF-8");         } catch (UnsupportedEncodingException e) {             e.printStackTrace();         }         url = u1 + u2;         imageViews.put(imageView, url);         Bitmap bitmap = memoryCache.get(url);         if (bitmap != null) {             if (isSrc)                 imageView.setImageBitmap(bitmap);             else                 imageView.setBackgroundDrawable(new BitmapDrawable(bitmap));         } else {             queuePhoto(url, imageView);             if (isSrc)                 imageView.setImageResource(stub_id);             else                 imageView.setBackgroundResource(stub_id);         }     }      private void queuePhoto(String url, ImageView imageView) {         PhotoToLoad p = new PhotoToLoad(url, imageView);         executorService.submit(new PhotosLoader(p));     }      private Bitmap getBitmap(String url) {         try {             File f = fileCache.getFile(url);             // 从sd卡             Bitmap b = onDecodeFile(f);             if (b != null)                 return b;             // 从网络             Bitmap bitmap = null;             System.out.println("ImageLoader-->download");             HttpUtil.CopyStream(url, f);             bitmap = onDecodeFile(f);              return bitmap;         } catch (Exception ex) {             ex.printStackTrace();             return null;         }     }      public Bitmap onDecodeFile(File f) {         try {             return BitmapFactory.decodeStream(new FileInputStream(f));         } catch (FileNotFoundException e) {             // TODO Auto-generated catch block             e.printStackTrace();         }         return null;     }      /**    * 解码图像用来减少内存消耗    *      * @param f    * @return    */     public Bitmap decodeFile(File f) {         try {             // 解码图像大小             BitmapFactory.Options o = new BitmapFactory.Options();             o.inJustDecodeBounds = true;             BitmapFactory.decodeStream(new FileInputStream(f), null, o);             // 找到正确的刻度值,它应该是2的幂。             final int REQUIRED_SIZE = 70;             int width_tmp = o.outWidth, height_tmp = o.outHeight;             int scale = 1;             while (true) {                 if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE)                     break;                 width_tmp /= 2;                 height_tmp /= 2;                 scale *= 2;             }             BitmapFactory.Options o2 = new BitmapFactory.Options();             o2.inSampleSize = scale;             return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);         } catch (FileNotFoundException e) {         }         return null;     }      /**    * 任务队列    *      * @author Scorpio.Liu    *      */     private class PhotoToLoad {         public String url;         public ImageView imageView;          public PhotoToLoad(String u, ImageView i) {             url = u;             imageView = i;         }     }      class PhotosLoader implements Runnable {         PhotoToLoad photoToLoad;          PhotosLoader(PhotoToLoad photoToLoad) {             this.photoToLoad = photoToLoad;         }          @Override         public void run() {             if (imageViewReused(photoToLoad))                 return;             Bitmap bmp = getBitmap(photoToLoad.url);             memoryCache.put(photoToLoad.url, bmp);             if (imageViewReused(photoToLoad))                 return;             BitmapDisplayer bd = new BitmapDisplayer(bmp, photoToLoad);             Activity a = (Activity) photoToLoad.imageView.getContext();             a.runOnUiThread(bd);         }     }      boolean imageViewReused(PhotoToLoad photoToLoad) {         String tag = imageViews.get(photoToLoad.imageView);         if (tag == null || !tag.equals(photoToLoad.url))             return true;         return false;     }      /**    * 显示位图在UI线程    *      * @author Scorpio.Liu    *      */     class BitmapDisplayer implements Runnable {         Bitmap bitmap;         PhotoToLoad photoToLoad;          public BitmapDisplayer(Bitmap b, PhotoToLoad p) {             bitmap = b;             photoToLoad = p;         }          public void run() {             if (imageViewReused(photoToLoad))                 return;             if (bitmap != null) {                 if (isSrc)                     photoToLoad.imageView.setImageBitmap(bitmap);                 else                     photoToLoad.imageView.setBackgroundDrawable(new BitmapDrawable(bitmap));             } else {                 if (isSrc)                     photoToLoad.imageView.setImageResource(stub_id);                 else                     photoToLoad.imageView.setBackgroundResource(stub_id);             }         }     }      public void clearCache() {         memoryCache.clear();         fileCache.clear();     }   }  

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

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