圖檔的異步加載,緩存應該是每個開發者都會遇到也會用到的技術。目前有很多優秀的開源架構,要說最被廣泛的使用的話,應該是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 == || outWidth == ) {
return ;
}
int width = options.outWidth;
int height = options.outHeight;
int inSampleSize = ;
if (height > outHeight || width > outWidth) {
int halfHeight = height / ;
int halfWidth = width / ;
while ((halfHeight / inSampleSize) >= outHeight && (halfWidth / inSampleSize) >= outWidth) {
inSampleSize *= ;
}
}
return inSampleSize;
}
}
LruCache的初始化方法:
//擷取應用的記憶體
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / );
//緩存的大小
int size = maxMemory /;
lruCache = new LruCache<String, Bitmap>(size) {
@Override
protected int sizeOf(String key, Bitmap value){
return value.getRowBytes() * value.getHeight() / ;
}
};
我們隻要重寫 sizeOf 方法就行了,計算biemap的大小。
DiskLruCache的初始化方法:
//sd卡緩存
long size = * * ;
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, , , 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 + ;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * + ;
private static final int KEEP_ALIVE = ;
//SD卡的緩存大小
private final static long DISK_SIZE = * * ;
private final int IO_BUFFER_SIZE = * ;
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();
@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() / );
int size = maxMemory / ;
lruCache = new LruCache<String, Bitmap>(size) {
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getByteCount() / ;
}
};
// 判斷是否有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, , , 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(, 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();
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();
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()) != -) {
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 = ; i < bytes.length; i++) {
String hex = Integer.toHexString( & bytes[i]);
if (hex.length() == ) {
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