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 = 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 = 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 = 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了,很方便~

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。