Android快取機制——DiskLruCache在硬碟中快取
阿新 • • 發佈:2018-12-18
一、Android中的快取策略 一般來說,快取策略主要包含快取的新增、獲取和刪除這三類操作。如何新增和獲取快取這個比較好理解,那麼為什麼還要刪除快取呢?這是因為不管是記憶體快取還是硬碟快取,它們的快取大小都是有限的。當快取滿了之後,再想其新增快取,這個時候就需要刪除一些舊的快取並新增新的快取。
因此LRU(Least Recently Used)快取演算法便應運而生,LRU是近期最少使用的演算法,它的核心思想是當快取滿時,會優先淘汰那些近期最少使用的快取物件。採用LRU演算法的快取有兩種:LrhCache和DiskLruCache,分別用於實現記憶體快取和硬碟快取,其核心思想都是LRU快取演算法。
三、使用 工具類DiskCacheUtil
package com.zhh.app; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Environment; import java.io.File; import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** * Created by Ivan on 2016/11/22. */ public class DiskCacheUtil { /** * 獲取App 快取路徑 * * @param context * @param uniqueName * @return */ public static File getDiskCacheDir(Context context, String uniqueName) { String cachePath = null; 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); } /** * 獲取APP版本號 * * @param context * @return */ public static int getAppVersionCode(Context context) { try { PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); return info.versionCode; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } return 1; } /** * 初始化DiskLruCache * * @param context */ public static DiskLruCache initDiskLruCache(Context context) { DiskLruCache mDiskLruCache = null; try { File cacheDir = getDiskCacheDir(context, "bitmap"); if (!cacheDir.exists()) { cacheDir.mkdirs(); } // 圖片佔的最大記憶體是20M mDiskLruCache = DiskLruCache.open(cacheDir, getAppVersionCode(context), 1, 20 * 1024 * 1024); } catch (IOException e) { e.printStackTrace(); } return mDiskLruCache; } /** * 獲取MD5 編碼 * 把圖片路徑 通過 MD5 轉換成 要儲存的檔名 * 將圖片的URL進行MD5編碼,編碼後的字串肯定是唯一的,並且只會包含0-F這樣的字元,完全符合檔案的命名規則 * * @param key * @return */ public static String getMd5String(String key) { String cacheKey; try { final MessageDigest mDigest = MessageDigest.getInstance("MD5"); mDigest.update(key.getBytes()); cacheKey = bytesToHexString(mDigest.digest()); } catch (NoSuchAlgorithmException e) { cacheKey = String.valueOf(key.hashCode()); } return cacheKey; } private static String bytesToHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { String hex = Integer.toHexString(0xFF & bytes[i]); if (hex.length() == 1) { sb.append('0'); } sb.append(hex); } return sb.toString(); } }
MainActivity中使用
package com.zhh.app; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.widget.Button; import android.widget.ImageView; import com.orhanobut.logger.Logger; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; public class MainActivity extends Activity { // 讀取圖片的按鈕 private Button button; // 刪除快取的按鈕 private Button button3; // 圖片 private ImageView imageView; // 上下文物件 private Context context; String imgurl = "http://img.my.csdn.net/uploads/201309/01/1378037235_7476.jpg"; // DiskLruCache物件 DiskLruCache diskLruCache; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); context = MainActivity.this; diskLruCache = DiskCacheUtil.initDiskLruCache(context); button = (Button)findViewById(R.id.button); button3 = (Button)findViewById(R.id.button3); imageView = (ImageView)findViewById(R.id.imageView); // 讀取圖片 button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { getData(); } }); // 移除快取 button3.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { remove(); } }); } private Handler handler = new Handler(){ @Override public void handleMessage(Message msg){ switch (msg.what) { case 1: try { // 從檔案中讀取 String key = DiskCacheUtil.getMd5String(imgurl); DiskLruCache.Snapshot snapShot = diskLruCache.get(key); if (snapShot != null) { InputStream is = snapShot.getInputStream(0); Bitmap bitmap = BitmapFactory.decodeStream(is); imageView.setImageBitmap(bitmap); } } catch (IOException e) { e.printStackTrace(); } break; } } }; /** * * 存入資料 存入的是 流 物件 * 從網路中讀取資料,儲存到檔案中 */ private void dataPut(){ new Thread(new Runnable() { @Override public void run() { try { String imageUrl = imgurl; String key =DiskCacheUtil.getMd5String(imageUrl); DiskLruCache.Editor editor = diskLruCache.edit(key); if (editor != null) { OutputStream outputStream = editor.newOutputStream(0); // 寫到這個流裡面 if (downloadUrlToStream(imageUrl, outputStream)) { editor.commit(); // 從網路中獲取資料,並且已經儲存到檔案中 // 發訊息,從檔案中讀取 handler.sendEmptyMessage(1); } else { editor.abort(); } } diskLruCache.flush(); } catch (Exception e) { e.printStackTrace(); } } }).start(); } /** * 下載圖片 * @param urlString * @param outputStream * @return */ private boolean downloadUrlToStream(String urlString, OutputStream outputStream) { HttpURLConnection urlConnection = null; BufferedOutputStream out = null; BufferedInputStream in = null; try { final URL url = new URL(urlString); urlConnection = (HttpURLConnection) url.openConnection(); in = new BufferedInputStream(urlConnection.getInputStream(), 8 * 1024); out = new BufferedOutputStream(outputStream, 8 * 1024); int b; while ((b = in.read()) != -1) { // 寫到這個流裡面 out.write(b); } return true; } catch (final IOException e) { e.printStackTrace(); } finally { if (urlConnection != null) { urlConnection.disconnect(); } try { if (out != null) { out.close(); } if (in != null) { in.close(); } } catch (final IOException e) { e.printStackTrace(); } } return false; } /** * 從檔案中讀取資料 * 取出的是 流 物件 */ private void getData(){ try { String key = DiskCacheUtil.getMd5String(imgurl); DiskLruCache.Snapshot snapShot = diskLruCache.get(key); // 從快取中讀取 if (snapShot != null) { Logger.t("111").d("從檔案中讀取"); InputStream is = snapShot.getInputStream(0); Bitmap bitmap = BitmapFactory.decodeStream(is); imageView.setImageBitmap(bitmap); }else{ // 從網路中讀取 Logger.t("111").d("從網路中讀取"); dataPut(); } } catch (IOException e) { e.printStackTrace(); } } /** * 移除快取 */ private void remove(){ try { String key = DiskCacheUtil.getMd5String(imgurl); diskLruCache.remove(key); } catch (IOException e) { e.printStackTrace(); } } }
activity_main.xml中
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical"
>
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="讀取資料"
/>
<Button
android:id="@+id/button3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="移除快取"
/>
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
開許可權:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />