亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > Android > 正文

android中圖片的三級緩存cache策略(內存/文件/網絡)

2020-04-11 12:13:47
字體:
來源:轉載
供稿:網友
1.簡介
現在android應用中不可避免的要使用圖片,有些圖片是可以變化的,需要每次啟動時從網絡拉取,這種場景在有廣告位的應用以及純圖片應用(比如百度美拍)中比較多。

現在有一個問題:假如每次啟動的時候都從網絡拉取圖片的話,勢必會消耗很多流量。在當前的狀況下,對于非wifi用戶來說,流量還是很貴的,一個很耗流量的應用,其用戶數量級肯定要受到影響。當然,我想,向百度美拍這樣的應用,必然也有其內部的圖片緩存策略??傊?,圖片緩存是很重要而且是必須的。

2.圖片緩存的原理
實現圖片緩存也不難,需要有相應的cache策略。這里我采用 內存-文件-網絡 三層cache機制,其中內存緩存包括強引用緩存和軟引用緩存(SoftReference),其實網絡不算cache,這里姑且也把它劃到緩存的層次結構中。當根據url向網絡拉取圖片的時候,先從內存中找,如果內存中沒有,再從緩存文件中查找,如果緩存文件中也沒有,再從網絡上通過http請求拉取圖片。在鍵值對(key-value)中,這個圖片緩存的key是圖片url的hash值,value就是bitmap。所以,按照這個邏輯,只要一個url被下載過,其圖片就被緩存起來了。

關于Java中對象的軟引用(SoftReference),如果一個對象具有軟引用,內存空間足夠,垃 圾回收器就不會回收它;如果內存空間不足了,就會回收這些對象的內存。只要垃圾回收器沒有回收它,該對象就可以被程序使用。軟引用可用來實現內存敏感的高 速緩存。使用軟引用能防止內存泄露,增強程序的健壯性。

從代碼上來說,采用一個ImageManager來負責圖片的管理和緩存,函數接口為public void loadBitmap(String url, Handler handler) ;其中url為要下載的圖片地址,handler為圖片下載成功后的回調,在handler中處理message,而message中包含了圖片的信息以及bitmap對象。ImageManager中使用的ImageMemoryCache(內存緩存)、ImageFileCache(文件緩存)以及LruCache(最近最久未使用緩存)會在后續文章中介紹。

3.代碼ImageManager.java
復制代碼 代碼如下:

/*
* 圖片管理
* 異步獲取圖片,直接調用loadImage()函數,該函數自己判斷是從緩存還是網絡加載
* 同步獲取圖片,直接調用getBitmap()函數,該函數自己判斷是從緩存還是網絡加載
* 僅從本地獲取圖片,調用getBitmapFromNative()
* 僅從網絡加載圖片,調用getBitmapFromHttp()
*
*/
public class ImageManager implements IManager
{
private final static String TAG = "ImageManager";

private ImageMemoryCache imageMemoryCache; //內存緩存

private ImageFileCache imageFileCache; //文件緩存

//正在下載的image列表
public static HashMap<String, Handler> ongoingTaskMap = new HashMap<String, Handler>();

//等待下載的image列表
public static HashMap<String, Handler> waitingTaskMap = new HashMap<String, Handler>();

//同時下載圖片的線程個數
final static int MAX_DOWNLOAD_IMAGE_THREAD = 4;

private final Handler downloadStatusHandler = new Handler(){
public void handleMessage(Message msg)
{
startDownloadNext();
}
};

public ImageManager()
{
imageMemoryCache = new ImageMemoryCache();
imageFileCache = new ImageFileCache();
}

/**
* 獲取圖片,多線程的入口
*/
public void loadBitmap(String url, Handler handler)
{
//先從內存緩存中獲取,取到直接加載
Bitmap bitmap = getBitmapFromNative(url);
if (bitmap != null)
{
Logger.d(TAG, "loadBitmap:loaded from native");
Message msg = Message.obtain();
Bundle bundle = new Bundle();
bundle.putString("url", url);
msg.obj = bitmap;
msg.setData(bundle);
handler.sendMessage(msg);
}
else
{
Logger.d(TAG, "loadBitmap:will load by network");
downloadBmpOnNewThread(url, handler);
}
}
/**
* 新起線程下載圖片
*/
private void downloadBmpOnNewThread(final String url, final Handler handler)
{
Logger.d(TAG, "ongoingTaskMap'size=" + ongoingTaskMap.size());

if (ongoingTaskMap.size() >= MAX_DOWNLOAD_IMAGE_THREAD)
{
synchronized (waitingTaskMap)
{
waitingTaskMap.put(url, handler);
}
}
else
{
synchronized (ongoingTaskMap)
{
ongoingTaskMap.put(url, handler);
}
new Thread()
{
public void run()
{
Bitmap bmp = getBitmapFromHttp(url);
// 不論下載是否成功,都從下載隊列中移除,再由業務邏輯判斷是否重新下載
// 下載圖片使用了httpClientRequest,本身已經帶了重連機制
synchronized (ongoingTaskMap)
{
ongoingTaskMap.remove(url);
}

if(downloadStatusHandler != null)
{
downloadStatusHandler.sendEmptyMessage(0);

}
Message msg = Message.obtain();
msg.obj = bmp;
Bundle bundle = new Bundle();
bundle.putString("url", url);
msg.setData(bundle);

if(handler != null)
{
handler.sendMessage(msg);
}
}
}.start();
}
}
/**
* 依次從內存,緩存文件,網絡上加載單個bitmap,不考慮線程的問題
*/
public Bitmap getBitmap(String url)
{
// 從內存緩存中獲取圖片
Bitmap bitmap = imageMemoryCache.getBitmapFromMemory(url);
if (bitmap == null)
{
// 文件緩存中獲取
bitmap = imageFileCache.getImageFromFile(url);
if (bitmap != null)
{
// 添加到內存緩存
imageMemoryCache.addBitmapToMemory(url, bitmap);
}
else
{
// 從網絡獲取
bitmap = getBitmapFromHttp(url);
}
}
return bitmap;
}

/**
* 從內存或者緩存文件中獲取bitmap
*/
public Bitmap getBitmapFromNative(String url)
{
Bitmap bitmap = null;
bitmap = imageMemoryCache.getBitmapFromMemory(url);

if(bitmap == null)
{
bitmap = imageFileCache.getImageFromFile(url);
if(bitmap != null)
{
// 添加到內存緩存
imageMemoryCache.addBitmapToMemory(url, bitmap);
}
}
return bitmap;
}

/**
* 通過網絡下載圖片,與線程無關
*/
public Bitmap getBitmapFromHttp(String url)
{
Bitmap bmp = null;

try
{
byte[] tmpPicByte = getImageBytes(url);

if (tmpPicByte != null)
{
bmp = BitmapFactory.decodeByteArray(tmpPicByte, 0,
tmpPicByte.length);
}
tmpPicByte = null;
}
catch(Exception e)
{
e.printStackTrace();
}

if(bmp != null)
{
// 添加到文件緩存
imageFileCache.saveBitmapToFile(bmp, url);
// 添加到內存緩存
imageMemoryCache.addBitmapToMemory(url, bmp);
}
return bmp;
}

/**
* 下載鏈接的圖片資源
*
* @param url
*
* @return 圖片
*/
public byte[] getImageBytes(String url)
{
byte[] pic = null;
if (url != null && !"".equals(url))
{
Requester request = RequesterFactory.getRequester(
Requester.REQUEST_REMOTE, RequesterFactory.IMPL_HC);
// 執行請求
MyResponse myResponse = null;
MyRequest mMyRequest;
mMyRequest = new MyRequest();
mMyRequest.setUrl(url);
mMyRequest.addHeader(HttpHeader.REQ.ACCEPT_ENCODING, "identity");
InputStream is = null;
ByteArrayOutputStream baos = null;
try {
myResponse = request.execute(mMyRequest);
is = myResponse.getInputStream().getImpl();
baos = new ByteArrayOutputStream();
byte[] b = new byte[512];
int len = 0;
while ((len = is.read(b)) != -1)
{
baos.write(b, 0, len);
baos.flush();
}
pic = baos.toByteArray();
Logger.d(TAG, "icon bytes.length=" + pic.length);
}
catch (Exception e3)
{
e3.printStackTrace();
try
{
Logger.e(TAG,
"download shortcut icon faild and responsecode="
+ myResponse.getStatusCode());
}
catch (Exception e4)
{
e4.printStackTrace();
}
}
finally
{
try
{
if (is != null)
{
is.close();
is = null;
}
}
catch (Exception e2)
{
e2.printStackTrace();
}
try
{
if (baos != null)
{
baos.close();
baos = null;
}
}
catch (Exception e2)
{
e2.printStackTrace();
}
try
{
request.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
}
return pic;
}

/**
* 取出等待隊列第一個任務,開始下載
*/
private void startDownloadNext()
{
synchronized(waitingTaskMap)
{
Logger.d(TAG, "begin start next");
Iterator iter = waitingTaskMap.entrySet().iterator();

while (iter.hasNext())
{

Map.Entry entry = (Map.Entry) iter.next();
Logger.d(TAG, "WaitingTaskMap isn't null,url=" + (String)entry.getKey());

if(entry != null)
{
waitingTaskMap.remove(entry.getKey());
downloadBmpOnNewThread((String)entry.getKey(), (Handler)entry.getValue());
}
break;
}
}
}

public String startDownloadNext_ForUnitTest()
{
String urlString = null;
synchronized(waitingTaskMap)
{
Logger.d(TAG, "begin start next");
Iterator iter = waitingTaskMap.entrySet().iterator();

while (iter.hasNext())
{
Map.Entry entry = (Map.Entry) iter.next();
urlString = (String)entry.getKey();
waitingTaskMap.remove(entry.getKey());
break;
}
}
return urlString;
}

/**
* 圖片變為圓角
* @param bitmap:傳入的bitmap
* @param pixels:圓角的度數,值越大,圓角越大
* @return bitmap:加入圓角的bitmap
*/
public static Bitmap toRoundCorner(Bitmap bitmap, int pixels)
{
if(bitmap == null)
return null;
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
final RectF rectF = new RectF(rect);
final float roundPx = pixels;
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}

public byte managerId()
{
return IMAGE_ID;
}
}
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美激情乱人伦| 欧美性xxxx极品高清hd直播| 欧美专区在线播放| www.xxxx欧美| 日韩亚洲欧美中文高清在线| 一区二区亚洲精品国产| 97精品视频在线| 国产日本欧美一区二区三区在线| 久久国产精品久久精品| 国产亚洲精品美女久久久| 欧美视频国产精品| 久久久黄色av| 综合网日日天干夜夜久久| 亚洲欧洲xxxx| 日韩av电影在线免费播放| 亲爱的老师9免费观看全集电视剧| 欧美亚洲午夜视频在线观看| 一区二区三区视频在线| 亚洲裸体xxxx| 国产精品久在线观看| 亚洲国产一区二区三区四区| 久久大大胆人体| 日韩美女免费视频| 在线播放国产一区二区三区| 欧美大片第1页| 亚洲一区美女视频在线观看免费| 国产日韩一区在线| 91亚洲精品久久久久久久久久久久| 久久亚洲综合国产精品99麻豆精品福利| 日韩在线视频观看| 欧美日韩在线第一页| 日韩中文视频免费在线观看| 91久久在线观看| 久久久www成人免费精品| 555www成人网| 欧美精品videos另类日本| 日韩在线视频网站| 国产极品精品在线观看| 亚洲成人a级网| 日韩中文视频免费在线观看| 欧美成人精品影院| 国产精品三级久久久久久电影| 欧美影院在线播放| 亚洲国产高清福利视频| 日本一区二区在线免费播放| 国产日韩欧美夫妻视频在线观看| 日韩69视频在线观看| 久久久久久久97| 午夜精品久久久久久久久久久久久| 91老司机精品视频| 欧洲亚洲在线视频| 亚洲三级黄色在线观看| 亚洲aa中文字幕| 福利精品视频在线| 欧美色道久久88综合亚洲精品| 97av在线视频| 国产精品va在线| 亚洲午夜久久久影院| 亚洲国产精品va在线看黑人| 91视频国产精品| 91视频-88av| 精品动漫一区二区| 97精品视频在线观看| 久久视频在线观看免费| 亚洲天堂一区二区三区| 亚洲成人性视频| 国产精品久久久久久亚洲影视| 欧美日韩精品中文字幕| 亚洲第一免费播放区| 92裸体在线视频网站| 毛片精品免费在线观看| 国产97在线观看| 97精品国产aⅴ7777| 国产一区二区三区在线观看网站| 久久国产精品久久久久| 日韩亚洲欧美中文在线| 亚洲一区制服诱惑| 色香阁99久久精品久久久| 91精品国产高清久久久久久91| 欧美电影免费观看| 国产精品自产拍在线观看| 国产精品扒开腿做爽爽爽男男| 久热99视频在线观看| 亚洲成人激情图| 萌白酱国产一区二区| 欧美精品成人91久久久久久久| 亚洲国产精品网站| 91久久久久久久久久| 日韩在线观看你懂的| 成人亚洲欧美一区二区三区| 色黄久久久久久| 成人www视频在线观看| 国产成人综合精品| 欧美激情网站在线观看| 狠狠做深爱婷婷久久综合一区| 日韩va亚洲va欧洲va国产| 亚洲精品第一国产综合精品| 久久久久久久999| 国内精品模特av私拍在线观看| 91精品国产成人www| 精品久久久久人成| 日韩精品在线免费观看| 国内揄拍国内精品少妇国语| 日韩欧美视频一区二区三区| 欧美成人性生活| 97视频在线观看免费| 久久久久久91| 国产精品视频永久免费播放| 亚洲视频专区在线| 日韩精品在线免费观看| 久久久综合av| 狠狠综合久久av一区二区小说| 97香蕉久久夜色精品国产| 福利视频导航一区| 国产欧美va欧美va香蕉在线| 精品视频—区二区三区免费| 精品夜色国产国偷在线| 中文字幕视频在线免费欧美日韩综合在线看| 亚洲激情在线视频| 亚洲女人初尝黑人巨大| 国产成人一区二区三区小说| 国产精品www色诱视频| 亚洲精品久久久久| 97超碰蝌蚪网人人做人人爽| 日本a级片电影一区二区| 69视频在线播放| 97香蕉超级碰碰久久免费软件| 欧洲成人免费aa| 久久国产精品久久久久久久久久| 午夜精品久久久久久久99热浪潮| 欧美日本高清一区| 日韩av电影手机在线观看| 亚洲国产精品悠悠久久琪琪| 日韩在线视频观看| 日韩美女中文字幕| 亚洲精品久久久久久久久久久久久| 午夜精品一区二区三区在线| 亚洲黄一区二区| 亚洲欧美成人网| 69av成年福利视频| 中文字幕精品av| 欧美大成色www永久网站婷| 欧美性jizz18性欧美| 久久久国产一区二区| 米奇精品一区二区三区在线观看| 精品激情国产视频| 欧美日韩日本国产| 久久九九全国免费精品观看| 欧美老女人性视频| 97在线免费观看视频| 亚洲激情中文字幕| 亚洲跨种族黑人xxx| 精品福利一区二区| 日韩成人av在线播放| 乱亲女秽乱长久久久| 久久中文字幕一区| 日韩高清中文字幕| 国产一区二区三区在线视频| 国产精品视频xxx| 在线视频亚洲欧美| 色99之美女主播在线视频| 亚洲黄页网在线观看| 日韩av在线免费播放| 欧美精品久久久久久久久久|