1. 程式人生 > >Android之DiskLruCache(快取工具)

Android之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

相關推薦

AndroidDiskLruCache快取工具

        DiskLruCache所有的資料都儲存在/storage/emulated/0/Android/data/應用包名/cache/XXX資料夾中(你也可以修改,但不建議這樣做,原因請繼續往下看),這個是android系統預設的應用快取位置,如果應用被刪除

Android 常用開發工具 SPUtils SharedPreference 工具

開發過程中難免會遇到如持久儲存使用者資訊等需求,而由於資料量很少感覺使用 Sql 有些殺雞用牛刀的感覺也有些累贅。所以善於使用 SharedPreference 可以幫助我們在本地儲存一些資料量少,又使用很頻繁的東西。 SPUtils 一個可以幫助我們很簡潔的使用  Sha

學習Android Studio開發工具Activity3框架3

接上文學習Android Studio開發工具之Activity3(框架2) 本篇介紹Android Studio提供的使用者偏好設定,新建一個Module命名為Prefs,選擇Settings Activity,如圖: 執行的效果如圖: Set

AndroidIntent

Android Intent 前一篇(Android之Intent(一))講解過A(它用來調起B界面,這裏先理解為父界面) 可以向B(這裏先理解為子界面), 本篇正好是一個逆反的過程 , 即B向A傳遞數據。 一 : 界面設計① ,A(activity_main.xml)重要控件:1‘ (TextVie

Mysql 性能分析mysqlreport工具

lin admin multi tar localhost per 必須 數據 log 一、mysqlreport 作用 進行MySQL的配置優化,首先必須找出MySQL的性能瓶頸所在;而SHOW STATUS輸出的報告正是用來計算性能瓶頸的參考數據。mysqlreport

Android破解學習十二—— GP錄影漢化過程及添加布局

## 前言 最近閒著發慌,想起了很久之前就想漢化的一款錄影APP,APP大小不到1MB,但是好用,本期就給大家帶來漢化的基本步驟以及如何在APP中新增我們漢化的資訊 ## 漢化思路 1. **查詢關鍵字** 關鍵字挺好找的,由於APP本身就是英文,我們找到某個英文單詞進行搜尋即可 2. **找到string.

Android面試集錦Activity知識整理

面試集錦是參考了慕課網BAT某大神的視訊。 本文分為四個部分: 1.Activity生命週期 2.Activity任務棧 3.Activity啟動模式 4.scheme跳轉協議 一、Activity的生命週期 什麼是Activity? android與使用者進行互動的時候,

Android面試集錦Service知識整理

本文主要講解兩個部分: 一、service的應用場景,以及和Thread的區別 二、開啟service的兩種方式以及區別 第一部分又可以分為: Service基礎: 1.Service是什麼? Service是一種可以在後臺執行長時間執行操作而沒有使用者介面的應用元件。 可

Android面試集錦Fragment知識整理

一、Fragment為什麼被稱為第五大元件 使用頻率高,ui切換效果好,更節省記憶體,因為其有自己的生命週期,所以也算不到四大元件裡取;fragment必須依附於activity存在。 二、Fragment載入到activity中的兩個方式 靜態載入,動態載入,(太基礎了不說了) 三

Android MVP 實踐理解篇

一.簡單介紹下MVP 1.什麼是mvp? 簡稱:MVP 全稱:Model-View-Presenter ;MVP 是從經典的模式MVC演變而來,它們的基本思想有相通的地方:Controller/Presenter負責邏輯的處理,Model提供資料,View負責顯示。 2.mv

Android許可權permission大全

一、說明 Android 6.0開始,Google將許可權分為兩類,一類是Normal Permission, 這類許可權一般不涉及使用者隱私,是不需要使用者進行授權的,比如手機震動、訪問網路等;另一類是Dangerous Permission,一般是涉及到使用者隱私的,需要使用者進行授權,比如

androidanimationanimationset、interpolator

一: animationset: 他是一個animation的一個子類,實際上是animation的一個集合。他將animation放到一個list集合中。需要對animation的基本設定可以通過animationset來設定。如果需要對一個控制元件進行多種動畫設定,可以採用animat

android 動畫 插值器

插值器 首先要了解為什麼需要插值器,因為在補間動畫中,我們一般只定義關鍵幀(首幀或尾幀),然後由系統自動生成中間幀,生成中間幀的這個過程可以成為“插值”。插值器定義了動畫變化的速率,提供不同的函式定義變化值相對於時間的變化規則,可以定義各種各樣的非線性變化函式,比如加速、減速等。下面是幾種常

解讀AndroidService1基礎知識

本文翻譯自Android官方文件 一個Service是一個長期可以在後臺執行(當然不需要提供UI)的應用元件。其它元件可以啟動service,即使切換到另一個應用,該service仍然可以在後臺執行。另外,其它元件可以繫結一個service進行互動,甚至可以進行程序間通訊(interproces

Android破解學習十四——【Unity3D】王牌大作戰破解

一、前言 今天帶來的是王牌大作戰的破解教程,遊戲下載的話,我是直接去TapTap官網下載的 支付寶內購破解用老套了,今天學點破解的新花樣吧!! 二、支付寶內購破解 支付寶的內購破解已經很熟悉了, 直接搜尋“9000”,之後找到程式碼,修改判斷條件即可,若不明白,請看我之前寫的部落格,Android破解

AndroidScaleGestureDetector縮放手勢檢測

1 package com.nan.scale; 2 3 import android.app.Activity; 4 import android.graphics.Bitmap; 5 import android.graphics.BitmapFactory; 6 impor

實現PHP伺服器+Android客戶端Retrofit+RxJava第三天Retrofit的配置以及快取的實現

上一篇講了介面,這篇文章就要講客戶端網路請求部分的內容了,主要用到的就是Retrofit+RxJava,其實準確來說是Retrofit+RxJava+OkHttp, 最新的Retrofit是2.0.2版本,原始碼地址:retrofit 學習retrofit:

AndroidFrescofacebook的強大Android圖片載入的框架

Fresco是Facebook最新推出的一款用於Android應用中展示圖片的強大圖片庫,可以從網路、本地儲存和本地資源中載入圖片。其中的Drawees可以顯示佔位符,直到圖片載入完成。而當圖片從螢幕上消失時,會自動釋放記憶體。 Fresco是Facebook開源Andr

Android 自定義控制元件命運抽獎轉盤

1 思路 首先肯定是要繪製扇形的,每一個獎品為一個扇形區分開,然後在扇形中得有當前獎品的說明,最後讓這個輪盤轉起來就行了。說起來很簡單,但是在繪製的時候,特別是繪製文字的時候還有有一些細節需要注意的,也不是難點,只是要理清楚那些地方應該怎麼去畫,怎麼獲取需要繪製的座標。  

Android學習第一篇 SurfaceView的原理以及使用場景

為什麼要使用SurfaceView來實現動畫? 因為View的繪圖存在以下缺陷: View缺乏雙緩衝機制 當程式需要更新View上的影象時,程式必須重繪View上顯示的整張圖片 新執行緒無法直接更新View元件 SurfaceView的繪圖機制