不積跬步,無以至千里,不積小流,無以成江海
阿新 • • 發佈:2019-02-03
我們在開發中用了許多載入圖片的框架都封裝了快取機制,圖片的三級快取的核心類就是LruCache類,嘗試手寫三級快取工具類:
/**
* 自定義的載入網路圖片工具:三級快取
* @author wangk
*
*/
public class MyBitmapUtils {
private Context context;
private LruCache<String, Bitmap> lruCache;
private File rootFile;//本地快取根目錄
private ExecutorService executorService;
public MyBitmapUtils(Context context) {
this.context = context;
/**
* maxSize:lruCache能管理的最大記憶體,此處設定為最大記憶體的1/8
*/
int maxSize = (int) (Runtime.getRuntime().maxMemory()/8);//Runtime.getRuntime().maxMemory()當前應用可使用的最大記憶體
lruCache = new LruCache<String, Bitmap>(maxSize){
/**
* 當前儲存的物件,bitmap,如何計算大小
*/
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getRowBytes() * bitmap.getHeight();//每一行的位元組個數*高度 = bitmap的大小
}
};
//本地快取到data/data
rootFile = context.getFilesDir();
executorService = Executors.newFixedThreadPool(3 );//建立固定大小的執行緒池,內部維護了3個執行緒
}
/**
* 展示網路圖片
* @param image : 展示的空間
* @param imageUrl: 圖片的url
*/
public void display(ImageView image, String imageUrl) {
/**
* 三級快取 (圖片)
* 1.記憶體快取 HashMap <key,value> key:圖片url,value:bitmap
* v4:LruCache 類似hashmap <key,value> lru演算法:less recent use,最少最近使用
* 2.本地快取 儲存sd卡,mnt/sdcard/zhbj_10/image/xxx.png
* xxx:圖片名稱,一般以圖片的 url+md5 命名
* url:唯一,還能通過url獲取本地快取圖片
* md5加密:為了避免url的特殊字元
* 3.網路快取
*
* 使用步驟: 遵循原則:優先獲取載入速度最快的快取資料
* 1.從記憶體中獲取,如果獲取到圖片,直接展示。如果獲取不到,從本地快取獲取
* 2.從本地快取中獲取,如果獲取到圖片,先載入到記憶體,然後展示。如果獲取不到,從網路獲取
* 3.從網路獲取,如果獲取到圖片,載入到記憶體中,然後展示,儲存到本地。
*/
//1.從記憶體中獲取圖片
Bitmap cacheBitmap = lruCache.get(imageUrl);
if(cacheBitmap!=null){
image.setImageBitmap(cacheBitmap);
System.out.println("從記憶體中獲取");
return ;
}
//2. 從本地獲取
String imageName = MD5Encoder.encode(imageUrl);//url+md5加密
File cacheFile = new File(rootFile, imageName);
if(cacheFile.exists() && cacheFile.length()!=0){
//載入到記憶體中,展示
Bitmap decodeFileBitmap = BitmapFactory.decodeFile(cacheFile.getAbsolutePath());
lruCache.put(imageUrl, decodeFileBitmap);
image.setImageBitmap(decodeFileBitmap);
System.out.println("從本地中獲取");
return;
}
//3.從網路獲取
int position = (Integer) image.getTag();
executorService.execute(new DownLoadRunnable(image,imageUrl,position));
System.out.println("從網路獲取");
}
class DownLoadRunnable implements Runnable{
private ImageView image;
private String imageUrl;
private int position;
/**
*
* @param image
* @param imageUrl
* @param position:請求的位置
*/
public DownLoadRunnable(ImageView image, String imageUrl, int position) {
this.image = image;
this.imageUrl = imageUrl;
this.position = position;
}
@Override
public void run() {
try {
SystemClock.sleep(1000);
//從網路獲取:HttpUrlConnection獲取網路圖片
URL url = new URL(imageUrl);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
//設定超時時間
httpURLConnection.setConnectTimeout(5*1000);
//設定請求方式
httpURLConnection.setRequestMethod("GET");
//獲取響應碼
int responseCode = httpURLConnection.getResponseCode();
if(responseCode == 200){//請求成功
InputStream inputStream = httpURLConnection.getInputStream();
final Bitmap decodeStreamBitmap = BitmapFactory.decodeStream(inputStream);
//儲存到記憶體
lruCache.put(imageUrl, decodeStreamBitmap);
//儲存到本地(bitmap物件如何轉換成本地檔案)
/**
* compress:壓縮
* format:壓縮格式:png、jgp
* quality:壓縮質量:0-100,0-完全壓縮,100-不壓縮
* outputStream:輸出流,寫到本地
*/
File cacheFile = new File(rootFile, MD5Encoder.encode(imageUrl));
OutputStream ops = new FileOutputStream(cacheFile);
decodeStreamBitmap.compress(CompressFormat.PNG, 100, ops);
//展示
MainActivity mainActivity = (MainActivity) context;
mainActivity.runOnUiThread(new Runnable()//Runnable在子執行緒還是主執行緒中執行,主要看呼叫者
{
@Override
public void run() {
int currentPosition = (Integer) image.getTag();
//請求的位置如果是當前顯示在螢幕上的位置
if(position == currentPosition){
image.setImageBitmap(decodeStreamBitmap);
}
}
});
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}