您的位置:首页 > 移动开发 > Android开发

android图片缓存实现(自定义ImageLoader)

2015-09-22 16:46 253 查看
先说一下图片的三级缓存:首先肯定是内存缓存,接着是本地缓存(SD卡),网络缓存。

再来看一看图片缓存的流程图:



下面上代码:代码中用到了线程池、还有内存中的软引用

import java.io.IOException;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import android.content.Context;
import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Message;
import android.support.v4.util.LruCache;
import android.widget.ImageView;

/**

 * @version 1.0
 * @创建时间:2014-8-5 下午5:41:03
 *
 */
public class ImageDownLoader {
 private static final int LOAD_SUCCESS = 1;
 /** 缓存Image的类,当存储Image的大小大于LruCache设定的值,系统自动释放内存 */
 private LruCache<String, Bitmap> lruCache;
 /** 文件操作工具类 */
 private FileUtils utils;

 private ThreadPoolExecutor executor;

 public ImageDownLoader(Context context) {
  super();
  // 开启线程池 最小线程数
  executor = new ThreadPoolExecutor(1, 4, 2, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>());
  // 获取系统分配给应用程序的最大内存
  int maxMemory = (int) Runtime.getRuntime().maxMemory();
  int maxSize = maxMemory / 8;
  lruCache = new LruCache<String, Bitmap>(maxSize) {

   @Override
   protected int sizeOf(String key, Bitmap value) {
    // 测量Bitmap的大小 默认返回图片数量
    return value.getRowBytes() * value.getHeight();
   }

  };

  utils = new FileUtils(context);
 }

 /**
  *
  * @Title: downLoader
  * @说 明: 加载图片   
  * @参 数: @param url
  * @参 数: @param loaderlistener
  * @参 数: @return
  * @return Bitmap 返回类型
  * @throws
  */
 public Bitmap downLoader(final ImageView imageView, final ImageLoaderlistener loaderlistener) {
  final String url = (String) imageView.getTag();  //首先得到图片设置的tag(用来区分图片错位的情况),所以在调用此类<span style="white-space:pre">						</span>   //之前,应该给ImageView控件设置Tag
  if (url != null) {
   final Bitmap bitmap = showCacheBitmap(url);//这里就是从缓存中去找图片
   if (bitmap != null) {                     //如果缓存中返回的图片为空的,则开启线程进行下载
    return bitmap;
   } else {
    final Handler handler = new Handler() {
     @Override
     public void handleMessage(Message msg) {
      super.handleMessage(msg);
      loaderlistener.onImageLoader((Bitmap) msg.obj, imageView);
     }
    };

    executor.execute(new Runnable() {

     @Override
     public void run() {
      Bitmap bitmap = HttpUtils.getBitmapFormUrl(url);
      if (bitmap != null) {                      //下载完毕之后将图片保存到缓存和本地,然后通知ImageView更新UI
       Message msg = handler.obtainMessage();
       msg.obj = bitmap;
       msg.what = LOAD_SUCCESS;
       handler.sendMessage(msg);
       try {
        utils.savaBitmap(url, bitmap);
       } catch (IOException e) {
        e.printStackTrace();
       }
       lruCache.put(url, bitmap);
      }
     }
    });
   }
  }
  return null;
 }

 /**
  *
  * @Title: showCacheBitmap
  * @说 明: 获取bitmap对象 : 内存中没有就去sd卡中去找
  * @参 数: @param url 图片地址
  * @参 数: @return
  * @return Bitmap 返回类型 图片
  * @throws
  */
 public Bitmap showCacheBitmap(String url) {
  Bitmap bitmap = getMemoryBitmap(url);
  if (bitmap != null) {
   return bitmap;
  } else if (utils.isFileExists(url) && utils.getFileSize(url) > 0) {
   bitmap = utils.getBitmap(url);
   lruCache.put(url, bitmap);
   return bitmap;
  }
  return null;
 }

 /**
  *
  * @Title: getMemoryBitmap
  * @说 明:获取内存中的图片
  * @参 数: @param url
  * @参 数: @return
  * @return Bitmap 返回类型
  * @throws
  */
 private Bitmap getMemoryBitmap(String url) {
  return lruCache.get(url);
 }

 public interface ImageLoaderlistener {
  public void onImageLoader(Bitmap bitmap,ImageView imageView);
 }

 /**
  *
  * @Title: cancelTask
  * @说 明:停止所有下载线程
  * @参 数:
  * @return void 返回类型
  * @throws
  */
 public void cancelTask() {
  if (executor != null) {
   executor.shutdownNow();
  }
 }

}


import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.os.Environment;

public class FileUtils {
 /**
  * sd卡的根目录
  */
 private static String mSdRootPath = Environment.getExternalStorageDirectory().getPath();
 /**
  * 手机的缓存根目录
  */
 private static String mDataRootPath = null;
 /**
  * 保存Image的目录名
  */
 private final static String FOLDER_NAME = "/tea/image";

 public FileUtils(Context context) {
  mDataRootPath = context.getCacheDir().getPath();
 }

 /**
  * 获取储存Image的目录
  *
  * @return
  */
 private String getStorageDirectory() {
  return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) ? mSdRootPath + FOLDER_NAME : mDataRootPath + FOLDER_NAME;
 }

 /**
  * 保存Image的方法,有sd卡存储到sd卡,没有就存储到手机目录
  *
  * @param fileName
  * @param bitmap
  * @throws IOException
  */
 public void savaBitmap(String url, Bitmap bitmap) throws IOException {
  if (bitmap == null) {
   return;
  }
  String path = getStorageDirectory();
  File folderFile = new File(path);
  if (!folderFile.exists()) {
   folderFile.mkdirs();
  }
  File file = new File(path + File.separator + getFileName(url));
  file.createNewFile();
  FileOutputStream fos = new FileOutputStream(file);
  bitmap.compress(CompressFormat.JPEG, 100, fos);
  fos.flush();
  fos.close();
 }

 /**
  * 从手机或者sd卡获取Bitmap
  *
  * @param fileName
  * @return
  */
 public Bitmap getBitmap(String url) {
  return BitmapFactory.decodeFile(getStorageDirectory() + File.separator + getFileName(url));
 }

 /**
  * 判断文件是否存在
  *
  * @param fileName
  * @return
  */
 public boolean isFileExists(String fileName) {
  return new File(getStorageDirectory() + File.separator + getFileName(fileName)).exists();
 }

 /**
  * 获取文件的大小
  *
  * @param fileName
  * @return
  */
 public long getFileSize(String url) {
  return new File(getStorageDirectory() + File.separator + getFileName(url)).length();
 }

 /**
  * 删除SD卡或者手机的缓存图片和目录
  */
 public void deleteFile() {
  File dirFile = new File(getStorageDirectory());
  if (!dirFile.exists()) {
   return;
  }
  if (dirFile.isDirectory()) {
   String[] children = dirFile.list();
   for (int i = 0; i < children.length; i++) {
    new File(dirFile, children[i]).delete();
   }
  }

  dirFile.delete();
 }

 /**
  *
  * @Title: getFileName
  * @说 明: 根据url截取文件名
  * @参 数: @param url
  * @参 数: @return
  * @return String 返回类型
  * @throws
  */
 public String getFileName(String url) {
  return url.substring(url.lastIndexOf("/") + 1);
 }

}
-------------------------------------------下载工具类-------------------------------------------------------------------

package com.qianfeng.android.utils;

import java.io.IOException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.util.EntityUtils;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

public class HttpUtils {
 /**
  *
  * @Title: getBitmapFormUrl
  * @说 明:从服务器获取Bitmap
  * @参 数: @param url
  * @参 数: @return
  * @return Bitmap 返回类型
  * @throws
  */
 public static Bitmap getBitmapFormUrl(String url) {
  Bitmap bitmap = null;
  HttpClient httpClient = new DefaultHttpClient();
  // 设置超时时间
  HttpConnectionParams.setConnectionTimeout(new BasicHttpParams(), 6 * 1000);
  HttpGet get = new HttpGet(url);
  try {
   HttpResponse response = httpClient.execute(get);
   if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
    HttpEntity entity = response.getEntity();
    bitmap = BitmapFactory.decodeStream(entity.getContent());
   }
  } catch (ClientProtocolException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  }
  return bitmap;
 }

 public static String getJsonFromServer(String url) {

  HttpClient httpClient = getHttpClient();
  HttpGet get = new HttpGet(url);

  try {
   HttpResponse response = httpClient.execute(get);
   if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
    HttpEntity entity = response.getEntity();
    return EntityUtils.toString(entity);
   }
  } catch (ClientProtocolException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  } finally {
   if (get != null) {
    get.abort();
   }
  }
  return null;

 }

 /**
  *
  * @Title: getHttpClient
  * @说 明:设置httpClient的一些参数
  * @参 数: @return
  * @return HttpClient 返回类型
  * @throws
  */
 private static HttpClient getHttpClient() {
  // 创建 HttpParams 以用来设置 HTTP 参数(这一部分不是必需的)
  HttpParams httpParams = new BasicHttpParams();
  // 设置连接超时和 Socket 超时,以及 Socket 缓存大小
  HttpConnectionParams.setConnectionTimeout(httpParams, 20 * 1000);
  HttpConnectionParams.setSoTimeout(httpParams, 20 * 1000);
  HttpConnectionParams.setSocketBufferSize(httpParams, 8192);
  // 设置重定向,缺省为 true
  HttpClientParams.setRedirecting(httpParams, true);
  // 设置 user agent
  String userAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2) Gecko/20100115 Firefox/3.6";
  HttpProtocolParams.setUserAgent(httpParams, userAgent);
  // 创建一个 HttpClient 实例
  // 注意 HttpClient httpClient = new HttpClient(); 是Commons HttpClient
  // 中的用法,在 Android 1.5 中我们需要使用 Apache 的缺省实现 DefaultHttpClient
  HttpClient httpClient = new DefaultHttpClient(httpParams);
  return httpClient;
 }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: