图片的异步加载,缓存应该是每个开发者都会遇到也会用到的技术。目前有很多优秀的开源框架,要说最被广泛的使用的话,应该是Universal-Image-Loader,很多应用反编译一下,都会看到他的身影。UIL的缓存原理:
引用:http://www.cnblogs.com/kissazi2/p/3931400.html
LruCache是android自带的缓存类,Lru的全称是Least Recently Used ,即近期最少使用,LruCache的原理就是当内存不够时,删除最少使用的数据。我们可以用LruCache和DiskLruCache自己实现一个。
思路:图片先从内存中去取,内存中没有的话,再从硬盘中取,再没有的话,从网上异步下载,压缩后,保存到硬盘和内存中。为了保证流畅性和节约内存,我们一般都不会直接去加载下载的原图,而是对其进行缩放。下面是图片处理的工具类。
package com.example.zet.joker;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import java.io.FileDescriptor;
/**
* Created by sean on 16/3/13.
*/
public class ImageUtil {
public ImageUtil() {}
public Bitmap decodeSampleBiemapFormFileDescroptor(FileDescriptor descriptor, int outWidth, int outHeight) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFileDescriptor(descriptor, null, options);
options.inSampleSize = calculateInSampleSize(options, outWidth, outHeight);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFileDescriptor(descriptor, null, options);
}
public int calculateInSampleSize(BitmapFactory.Options options, int outWidth, int outHeight) {
if (outHeight == 0 || outWidth == 0) {
return 1;
}
int width = options.outWidth;
int height = options.outHeight;
int inSampleSize = 1;
if (height > outHeight || width > outWidth) {
int halfHeight = height / 2;
int halfWidth = width / 2;
while ((halfHeight / inSampleSize) >= outHeight && (halfWidth / inSampleSize) >= outWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
}
LruCache的初始化方法:
//获取应用的内存
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
//缓存的大小
int size = maxMemory /4;
lruCache = new LruCache<String, Bitmap>(size) {
@Override
protected int sizeOf(String key, Bitmap value){
return value.getRowBytes() * value.getHeight() / 1024;
}
};
我们只要重写 sizeOf 方法就行了,计算biemap的大小。
DiskLruCache的初始化方法:
//sd卡缓存
long size = 1024 * 1024 * 50;
boolean sdCardExist = Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
File diskDir;
if (!sdCardExist)
diskDir = new File(Environment.getRootDirectory() + "/sean/");
else
diskDir = new File(Environment.getExternalStorageDirectory() + "/sean/");
if (!diskDir.exists()) {
diskDir.mkdirs();
}
try {
diskLruCache = DiskLruCache.open(diskDir, 1, 1, size);
} catch (IOException e) {
e.printStackTrace();
}
贴起来好麻烦,代码全放上吧,看注释
public class ImageLoader {
private static ImageLoader imageLoader;
private static final String TAG = "ImageLoader";
//线程池的配置
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE = 10;
//SD卡的缓存大小
private final static long DISK_SIZE = 1024 * 1024 * 50;
private final int IO_BUFFER_SIZE = 8 * 1024;
private LruCache<String, Bitmap> lruCache;
private DiskLruCache diskLruCache;
private Context context;
private ImageUtil imageUtil = new ImageUtil();
;
private static final ThreadFactory factory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "thread: " + mCount.getAndIncrement());
}
};
public static ImageLoader getInstance(Context context) {
if (null == imageLoader) {
imageLoader = new ImageLoader(context);
}
return imageLoader;
}
//初始化线程池
public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor
(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), factory);
public ImageLoader(Context context) {
context = context.getApplicationContext();
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
int size = maxMemory / 3;
lruCache = new LruCache<String, Bitmap>(size) {
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getByteCount() / 1024;
}
};
// 判断是否有SD卡
boolean sdCardExist = Environment.getExternalStorageState().equals(
android.os.Environment.MEDIA_MOUNTED);
File diskDir;
if (!sdCardExist) {
diskDir = new File(Environment.getRootDirectory()
+ "/sean/");
} else {
diskDir = new File(Environment.getExternalStorageDirectory()
+ "/sean/");
}
if (!diskDir.exists()) {
diskDir.mkdirs();
}
try {
diskLruCache = DiskLruCache.open(diskDir, 1, 1, DISK_SIZE);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 异步加载图片的方法
*
* @param url
* @param imageView
* @param outWidth
* @param outHeight
*/
public void bindBitmap(final String url, final ImageView imageView, final int outWidth, final int outHeight) {
imageView.setTag(url);
//将地址转成MD5编码 方便存储和获取 因为有些地址含有特殊符号
String key = hashKeyFromUrl(url);
//先去内存中查找
Bitmap bitmap = getBitmapFromMemroy(key);
if (null != bitmap) {
imageView.setImageBitmap(bitmap);
return;
}
//开始异步获取
Runnable runnable = new Runnable() {
@Override
public void run() {
Bitmap bitmap1 = loadBitmap(url, outWidth, outHeight);
if (null != bitmap1) {
LoaderResult result = new LoaderResult(imageView, bitmap1, url);
Message msg = mMainHandler.obtainMessage(1, result);
msg.sendToTarget();
}
}
};
THREAD_POOL_EXECUTOR.execute(runnable);
}
/**
* 从SD卡中查找缓存 没有的话 开始下载
* @param url
* @param outWidth
* @param outHeight
* @return
*/
private Bitmap loadBitmap(String url, int outWidth, int outHeight) {
try {
String key = hashKeyFromUrl(url);
//SD卡中查找
Bitmap bitmap = loadBitmapDiskCache(key, outWidth, outHeight);
if (null != bitmap) {
return bitmap;
}
//冲网络上下载
bitmap = loadBitmapFromHttp(url, outWidth, outHeight);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 存入内存
*
* @param key
* @param bitmap
*/
private void addBitmapToMemoryCache(String key, Bitmap bitmap) {
if (null == getBitmapFromMemroy(key)) {
lruCache.put(key, bitmap);
}
}
/**
* 内存取
*
* @param key
*/
private Bitmap getBitmapFromMemroy(String key) {
return lruCache.get(key);
}
/**
* 本地缓存
*
* @param url
*/
private Bitmap loadBitmapFromHttp(String url, int outWidth, int outHeight) {
try {
String key = hashKeyFromUrl(url);
DiskLruCache.Editor editor = diskLruCache.edit(key);
if (editor != null) {
OutputStream outputStream = editor.newOutputStream(0);
if (dowanloadUriToStream(url, outputStream)) {
editor.commit();
} else {
editor.abort();
}
}
diskLruCache.flush();
} catch (IOException e) {
e.printStackTrace();
}
return loadBitmapDiskCache(url, outWidth, outHeight);
}
/**
* 本地缓存 读取
* @param outWidth
* @param outHeight
* @return
*/
private Bitmap loadBitmapDiskCache(String key, int outWidth, int outHeight) {
Bitmap bitmap = null;
try {
DiskLruCache.Snapshot snapshot = diskLruCache.get(key);
if (snapshot != null) {
FileInputStream fileInputStream = (FileInputStream) snapshot.getInputStream(0);
FileDescriptor fileDescriptor = fileInputStream.getFD();
//更具需要的大小 进行压缩
bitmap = imageUtil.decodeSampleBiemapFormFileDescroptor(fileDescriptor, outWidth, outHeight);
if (null != bitmap) {
//加入lruCache
addBitmapToMemoryCache(key, bitmap);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
/**
* 下载类 返回输出流
*
* @param url
* @param outputStream
* @return
*/
public boolean dowanloadUriToStream(String url, OutputStream outputStream) {
HttpURLConnection urlConnection = null;
BufferedOutputStream out = null;
BufferedInputStream in = null;
try {
URL str = new URL(url);
urlConnection = (HttpURLConnection) str.openConnection();
in = new BufferedInputStream(urlConnection.getInputStream(), IO_BUFFER_SIZE);
out = new BufferedOutputStream(outputStream, IO_BUFFER_SIZE);
int b;
while ((b = in.read()) != -1) {
out.write(b);
}
return true;
} catch (Exception e) {
e.printStackTrace();
} finally {
urlConnection.disconnect();
try {
if (null != out) {
out.close();
}
if (null != in) {
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return false;
}
private String hashKeyFromUrl(String url) {
String key = null;
try {
MessageDigest digest = MessageDigest.getInstance("MD5");
digest.update(url.getBytes());
key = bytesToHexString(digest.digest());
} catch (Exception e) {
e.printStackTrace();
}
return key;
}
private String bytesToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(0xFF & bytes[i]);
if (hex.length() == 1) {
sb.append("0");
}
sb.append(hex);
}
return sb.toString();
}
private Handler mMainHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
LoaderResult result = (LoaderResult) msg.obj;
ImageView imageView = result.getImageView();
String url = (String) imageView.getTag();
if (url.endsWith(result.getUrl())) {
imageView.setImageBitmap(result.getBitmap());
}
}
};
}
这方面在面试的时候问的也好像比较多,所以可以花些时间去了解下。下面是项目代码:
http://download.csdn.net/detail/zhuwentao16/9462142