Android 快取工具 DiskLruCache 學習筆記
DiskLruCache是一個十分好用的android快取工具,我們可以從GitHub上下載其原始碼:https://github.com/JakeWharton/DiskLruCache
DiskLruCache所有的資料都儲存在/storage/emulated/0/Android/data/應用包名/cache/XXX資料夾中(你也可以修改,但不建議這樣做,原因請繼續往下看),這個是android系統預設的應用快取位置,如果應用被刪除,這個檔案也會一起被刪除,避免應用刪除後有殘留資料的問題。同時,由於資料沒有儲存在硬碟裡,所以不會影響系統效能,在sd卡里,你可以儲存任意多資料。
由於DiskLruCache是被final修飾的,因此不可以直接通過new獲得它的例項,我們使用它的open方法獲得它的一個例項:
public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)
open方法需要四個引數,第一個是快取檔案檔案的位置,通過下面的方法可得到:
private File getDiskCacheDir(Context context, String uniqueName) { String cachePath; //如果sd卡存在並且沒有被移除 if (Environment.MEDIA_MOUNTED.equals(Environment .getExternalStorageState()) || !Environment.isExternalStorageRemovable()) { cachePath = context.getExternalCacheDir().getPath(); } else { cachePath = context.getCacheDir().getPath(); } return new File(cachePath + File.separator + uniqueName); }
第二個引數是應用程式的版本號,要傳入版本號是因為如果應用升級快取會被清除掉。通過下面的方法可以獲得程式的版本號:
private int getAppVersion(Context context) { try { PackageInfo info = context.getPackageManager().getPackageInfo( context.getPackageName(), 0); return info.versionCode; } catch (NameNotFoundException e) { e.printStackTrace(); } return 1; }
第三個參數列示同一個key可以對應多少個快取檔案,一般情況下我們都是傳1,這樣key和快取檔案一一對應,查詢和移除都會比較方便。
第四個參數列示最大可以快取多少位元組的資料。
開啟了DiskLruCache之後,我們可以看看怎麼向DiskLruCache中快取資料:
先來看看從網上down一張圖片:
private boolean downloadImg(final String urlStr, final OutputStream outputStream) { HttpURLConnection conn = null; BufferedOutputStream out = null; BufferedInputStream in = null; try { URL url = new URL(urlStr); conn = (HttpURLConnection) url.openConnection(); in = new BufferedInputStream(conn.getInputStream(), 8 * 1024); out = new BufferedOutputStream(outputStream, 8 * 1024); int len = 0; while ((len = in.read()) != -1) { out.write(len); } return true; } catch (IOException e) { e.printStackTrace(); } finally { if (conn != null) conn.disconnect(); try { if (out != null) out.close(); } catch (IOException e) { e.printStackTrace(); } try { if (in != null) in.close(); } catch (IOException e) { e.printStackTrace(); } } return false; }
這是一個簡單的聯網down圖片程式碼,拿到圖片後就可以快取到本地了,但是對於每一個儲存資源都需要有一個key,這個key要是唯一的,而且這個key 最長120個字元,且只能包括a-z,0-9,下劃線以及減號,一次我們可以採用Java中的UUID來得到key,也可以使用MD5加密網址得到一個 key,我這裡採用md5,方法如下:
public class MD5Util { public final static String md5(String pwd) { //用於加密的字元 char md5String[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; try { //使用平臺的預設字符集將此 String 編碼為 byte序列,並將結果儲存到一個新的 byte陣列中 byte[] btInput = pwd.getBytes(); // 獲得指定摘要演算法的 MessageDigest物件,此處為MD5 //MessageDigest類為應用程式提供資訊摘要演算法的功能,如 MD5 或 SHA 演算法。 //資訊摘要是安全的單向雜湊函式,它接收任意大小的資料,並輸出固定長度的雜湊值。 MessageDigest mdInst = MessageDigest.getInstance("MD5"); //System.out.println(mdInst); //MD5 Message Digest from SUN, <initialized> //MessageDigest物件通過使用 update方法處理資料, 使用指定的byte陣列更新摘要 mdInst.update(btInput); //System.out.println(mdInst); //MD5 Message Digest from SUN, <in progress> // 摘要更新之後,通過呼叫digest()執行雜湊計算,獲得密文 byte[] md = mdInst.digest(); //System.out.println(md); // 把密文轉換成十六進位制的字串形式 int j = md.length; //System.out.println(j); char str[] = new char[j * 2]; int k = 0; for (int i = 0; i < j; i++) { // i = 0 byte byte0 = md[i]; //95 str[k++] = md5String[byte0 >>> 4 & 0xf]; // 5 str[k++] = md5String[byte0 & 0xf]; // F } //返回經過加密後的字串 return new String(str); } catch (Exception e) { e.printStackTrace(); return null; } } }
各位看官在使用的時候記得把md5String[]中大寫的字母改為小寫,因為key中如果有大寫字母驗證會不通過。當然,你也可以修改DiskLruCache的原始碼從而讓它支援大寫字母,修改的地方:
現在萬事俱備,我們來把圖片快取起來,由於聯網是好事操作,所以要在新執行緒中完成,完整的方法如下:
private void cacheImg() { new Thread(new Runnable() { @Override public void run() { String key = MD5Util.md5(IMGIP); try { DiskLruCache.Editor editor = mDiskLruCache.edit(key); if (editor != null) { OutputStream out = editor.newOutputStream(0); if (downloadImg(IMGIP, out)) { //提交 editor.commit(); } else { //撤銷操作 editor.abort(); } } /** * 這個方法用於將記憶體中的操作記錄同步到日誌檔案(也就是journal檔案)當中。 * 這個方法非常重要,因為DiskLruCache能夠正常工作的前提就是要依賴於journal檔案中的內容。 * 並不是每次寫入快取都要呼叫一次flush()方法的,頻繁地呼叫並不會帶來任何好處, * 只會額外增加同步journal檔案的時間。 * 比較標準的做法就是在Activity的onPause()方法中去呼叫一次flush()方法就可以了 */ mDiskLruCache.flush(); } catch (IOException e) { e.printStackTrace(); } } }).start(); }
editor.newOutputStream(0);方法有一個引數,檢視原始碼我們知道這個引數必須大於0並且小於valueCount,前文中valueCount我們已經設定為1了,所以這裡只能取值0。這個時候開啟你的快取資料夾,/storage/emulated/0/Android/data/應用包名/cache/XXX,裡邊已經有了我們快取的資料了:
好了,資料存下來了,接下來就是讀取,每一個快取檔案都對應一個key,讀取就是根據這個key來讀取:
private void showImg() { String key = MD5Util.md5(IMGIP); try { DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key); if(snapShot!=null){ InputStream is = snapShot.getInputStream(0); Bitmap bitmap = BitmapFactory.decodeStream(is); im.setImageBitmap(bitmap); } } catch (IOException e) { e.printStackTrace(); } }
讀取的時候我們最先拿到的是一個Snapshot 物件,再根據我們之前傳入的引數0拿到快取檔案的流,最後把流轉換為圖片。
到這裡大家可能就明白了,之前的editor.newOutputStream(0);方法為什麼會有一個0的引數了,相當於一個標識,讀取時也傳入引數0才能讀到我們想要的資料。(加入我們的key與快取檔案不是一一對應,也就是我們一開始的open方法中傳入的不是valueCount的值不是 1,那麼一個key對應多個快取檔案我們要怎麼區分?就是通過這種方式,有興趣的同學檢視原始碼就一目瞭然了)。
下來就是清除快取了,看方法:
private void clearCache() { String key = MD5Util.md5(IMGIP); try { mDiskLruCache.remove(key); } catch (IOException e) { e.printStackTrace(); } }
根據快取檔案的key,呼叫remove方法,將該快取檔案移除。
下來是檢視快取大小:
像鳳凰新聞客戶端中顯示快取大小,這個數值我們可以通過size()方法直接拿到:
private void getCacheSize() { tv.setText(mDiskLruCache.size()+""); }
大家應該看到了鳳凰新聞還有一個功能就是清除快取,這個功能直接呼叫delete方法就能實現:
private void deleteAll() { /** * 這個方法用於將所有的快取資料全部刪除 * 其實只需要呼叫一下DiskLruCache的delete()方法就可以實現了。 * 會刪除包括日誌檔案在內的所有檔案 */ try { mDiskLruCache.delete(); } catch (IOException e) { e.printStackTrace(); } }
所有功能都完成之後,我們要記得在onDestory方法中關閉DiskLruCache。
@Override protected void onDestroy() { super.onDestroy(); /** * 這個方法用於將DiskLruCache關閉掉,是和open()方法對應的一個方法。 * 關閉掉了之後就不能再呼叫DiskLruCache中任何操作快取資料的方法, * 通常只應該在Activity的onDestroy()方法中去呼叫close()方法。 */ try { mDiskLruCache.close(); } catch (IOException e) { e.printStackTrace(); } }
到此,我想大家已經基本會用這個東東了吧。
最後奉上本文原始碼下載地址http://pan.baidu.com/s/1kTzSHtd
相關文章
- Android:跟著實戰專案學快取策略之DiskLruCache詳談Android快取
- 優雅的構建 Android 專案之磁碟快取(DiskLruCache)Android快取
- Android 學習筆記雜記Android筆記
- Android學習筆記·ANRAndroid筆記
- Android學習筆記·HandlerAndroid筆記
- Android學習筆記·ADBAndroid筆記
- Android學習筆記一Android筆記
- Android SQLite學習筆記AndroidSQLite筆記
- Android Linker學習筆記Android筆記
- Android Studio學習筆記Android筆記
- Springcloud學習筆記68--springboot 整合Caffeine 本地快取GCCloud筆記Spring Boot快取
- Android 學習筆記核心篇Android筆記
- Android Gradle 學習筆記整理AndroidGradle筆記
- Android 學習筆記思考篇Android筆記
- 2018.03.06 Android Handler學習筆記Android筆記
- Android 開發學習筆記Android筆記
- CDN快取學習筆記,讀騰訊雲的一些心得和整理筆記快取筆記
- Android 學習筆記架構篇Android筆記架構
- React Native Android學習筆記 - 2015React NativeAndroid筆記
- 2018.03.16、Android-IntentService學習筆記AndroidIntent筆記
- Android環境搭建學習筆記Android筆記
- HTTP快取筆記(1)HTTP快取筆記
- Android 擼一個快取工具類Android快取
- Redis面試高頻45題筆記:基礎+快取雪崩+哨兵+叢集+Reids學習筆記Redis面試筆記快取
- Android菜鳥學習js筆記一AndroidJS筆記
- Android卡頓優化學習筆記Android優化筆記
- 2018.03.30、Android-ObjectBox學習筆記1AndroidObject筆記
- SDWebImage 快取機制(筆記)Web快取筆記
- Android 學習筆記之單選按鈕(RadioButton)和核取方塊(CheckBox)Android筆記
- Android學習筆記(建立Menu,Intent的使用)Android筆記Intent
- Android學習筆記-Activity的啟動模式Android筆記模式
- Guava學習:Cache快取Guava快取
- MogDB/openGauss學習筆記-獲取物件DDL筆記物件
- numpy的學習筆記\pandas學習筆記筆記
- Android學習筆記之build.gradle檔案Android筆記UIGradle
- 《分散式快取》讀書筆記二分散式快取筆記
- Django筆記三十三之快取操作Django筆記快取
- 學習筆記筆記