使用Android新式LruCache緩存圖片,基于線程池異步加載圖片
來源:程序員人生 發(fā)布時(shí)間:2015-03-31 08:33:51 閱讀次數(shù):2838次
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;
import android.support.v4.util.LruCache;
import android.util.Log;
import android.widget.ImageView;
/*
* 使用Android新式LruCache緩存圖片,基于線程池異步加載圖片。
* 基本思路:開辟1個(gè)線程池下載網(wǎng)絡(luò)圖片,同時(shí)創(chuàng)建1個(gè)LruCache作為Android內(nèi)存緩存混存圖片。
* 上層利用傳遞過來1個(gè)URL要求從該URL下載圖片時(shí),首先檢查L(zhǎng)ruCache中是不是存在以該URL為索引的緩存圖片,
* 若有,則直接從緩存中讀出來返回給上層利用;若沒有,此時(shí)再開辟線程下載,下載完成后將此bitmap埋入緩存。
* 備注:圖片的url作為緩存圖片時(shí)LruCache的 Key。
* LruCache在內(nèi)存中的緩存模型為<K,V>。
*/
public class AsyncImageLoader {
private ExecutorService pool;
private Handler handler;
private ImageLoadedListener listener;
private final int WHAT = 0xe001;
// 默許的線程池容量
private int DEFAULT_TASK_NUMBER = 10;
// 網(wǎng)絡(luò)超時(shí)時(shí)間:30秒
private static int TIMEOUT = 30 * 1000;
private LruCache<String, Bitmap> mMemoryCache;
// 4MB緩存大小
private final int CACHE_SIZE = 4 * 1024 * 1024;
public AsyncImageLoader(int asyncTaskNumber) {
initialization(asyncTaskNumber);
}
public AsyncImageLoader() {
// 默許的構(gòu)造函數(shù)初始化線程池容量為:TASK_NUMBER
initialization(DEFAULT_TASK_NUMBER);
}
// 初始化
private void initialization(int asyncTaskNumber) {
mMemoryCache = new LruCache<String, Bitmap>(CACHE_SIZE) {
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
};
// 創(chuàng)建容量為 asyncTaskNumber 的線程池。
pool = Executors.newFixedThreadPool(asyncTaskNumber);
handler = new Handler() {
@Override
public void handleMessage(Message message) {
switch (message.what) {
case WHAT:
listener.imageLoaded((Bitmap) message.obj);
}
}
};
}
// 異步設(shè)置1個(gè)ImagView的Bitmap(該ImageView的Bitmap從網(wǎng)絡(luò)加載)
// 該方法為public,作為該工具類的外部調(diào)用接口。
public void asyncSetImageBitmap(String url, final ImageView view) {
download(url, new ImageLoadedListener() {
@Override
public void imageLoaded(Bitmap bitmap) {
view.setImageBitmap(bitmap);
}
});
}
// 異步的從1個(gè)URL下載1個(gè)Bitmap。
// 下載成功后,回調(diào)imageLoaded(Bitmap bitmap, String url);
// 該方法為public,作為該工具類的外部調(diào)用接口。
public void download(String url, ImageLoadedListener listener) {
this.listener = listener;
// 首先從緩存中檢查是不是存在以u(píng)rl為key的bitmap。
// 若有,則直接從緩存中讀取使用,不再使用線程重復(fù)加載。
Bitmap bmp = mMemoryCache.get(url);
if (bmp != null) {
Log.d("讀取緩存", url + " 已緩存,不必重復(fù)下載!");
sendResult(bmp);
return;
}
Thread t = new DownloadThread(url);
pool.execute(t);
}
// 開辟1個(gè)下載線程
private class DownloadThread extends Thread {
private String url;
public DownloadThread(String url) {
this.url = url;
}
@Override
public void run() {
Bitmap bmp = loadBitmapFromURL(url);
// 將新的bitmap埋入緩存
mMemoryCache.put(url, bmp);
sendResult(bmp);
}
}
// 發(fā)送消息通知:bitmap已下載完成。
private void sendResult(Bitmap bitmap) {
Message message = handler.obtainMessage();
message.what = WHAT;
message.obj = bitmap;
handler.sendMessage(message);
}
// 回調(diào)函數(shù)
public interface ImageLoadedListener {
public void imageLoaded(Bitmap bitmap);
}
// 給定1個(gè)URL,從這個(gè)URL下載Bitmap
public static Bitmap loadBitmapFromURL(String url) {
if (!url.contains("http://")) {
url = "http://" + url;
}
Log.d("線程:" + Thread.currentThread().getId(), "開始下載: " + url);
Bitmap bmp = null;
try {
byte[] imageBytes = loadRawDataFromURL(url);
bmp = BitmapFactory.decodeByteArray(imageBytes, 0,
imageBytes.length);
} catch (Exception e) {
e.printStackTrace();
}
return bmp;
}
// 給定1個(gè)URL,從這個(gè)URL下載原始數(shù)據(jù)塊。
public static byte[] loadRawDataFromURL(String u) throws Exception {
URL url = new URL(u);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// 配置基礎(chǔ)網(wǎng)絡(luò)鏈接參數(shù)
conn.setConnectTimeout(TIMEOUT);
conn.setReadTimeout(TIMEOUT);
InputStream is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
final int BUFFER_SIZE = 1024 * 5;
final int EOF = ⑴;
int c;
byte[] buf = new byte[BUFFER_SIZE];
while (true) {
c = bis.read(buf);
if (c == EOF)
break;
baos.write(buf, 0, c);
}
conn.disconnect();
is.close();
byte[] data = baos.toByteArray();
baos.flush();
return data;
}
}
生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對(duì)您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)