Android快取機制——LruCache在記憶體中快取
阿新 • • 發佈:2019-02-04
一、Android中的快取策略
一般來說,快取策略主要包含快取的新增、獲取和刪除這三類操作。如何新增和獲取快取這個比較好理解,那麼為什麼還要刪除快取呢?這是因為不管是記憶體快取還是硬碟快取,它們的快取大小都是有限的。當快取滿了之後,再想其新增快取,這個時候就需要刪除一些舊的快取並新增新的快取。
因此LRU(Least Recently Used)快取演算法便應運而生,LRU是近期最少使用的演算法,它的核心思想是當快取滿時,會優先淘汰那些近期最少使用的快取物件。採用LRU演算法的快取有兩種:LrhCache和DisLruCache,分別用於實現記憶體快取和硬碟快取,其核心思想都是LRU快取演算法。
二、LruCache的實現原理
最近最少使用演算法,LruCache的核心思想很好理解,就是要維護一個快取物件列表,其中物件列表的排列方式是按照訪問順序實現的,即一直沒訪問的物件,將放在隊尾,即將被淘汰。而最近訪問的物件將放在隊頭,最後被淘汰。
三、LruCache的使用
工具類 ImageDownloader
package com.zhh.app; import android.graphics.Bitmap; import android.util.LruCache; import com.orhanobut.logger.Logger; /** * 工具類 */ public class ImageDownloader { private static final String TAG = "TextDownload"; private LruCache<String, Bitmap> lruCache; /** * 例項化物件 */ public ImageDownloader() { long maxMemory = Runtime.getRuntime().maxMemory(); int cacheSize = (int) (maxMemory / 8); lruCache = new LruCache<String, Bitmap>(cacheSize) { @Override protected int sizeOf(String key, Bitmap value) { return value.getByteCount(); } }; } /** * 把Bitmap物件加入到快取中 * */ public void addBitmapToMemory(String key, Bitmap bitmap) { if (getBitmapFromMemCache(key) == null) { lruCache.put(key, bitmap); } } /** * 從快取中得到Bitmap物件 */ public Bitmap getBitmapFromMemCache(String key) { Logger.t("111").d("lrucache size: " + lruCache.size()); return lruCache.get(key); } /** * 從快取中刪除指定的Bitmap */ public void removeBitmapFromMemory(String key) { lruCache.remove(key); } }
在 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.util.Log; import android.view.View; import android.widget.Button; import android.widget.ImageView; import com.orhanobut.logger.Logger; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; public class MainActivity extends Activity { // imageDownloader 物件 private ImageDownloader imageDownloader; // imageView圖片 private ImageView imageView; // 按鈕 private Button button; // 上下文 private Context context; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initOnclick(); } /** * 初始化控制元件 */ private void initView() { imageView = (ImageView) findViewById(R.id.imageView); button = (Button) findViewById(R.id.button); imageDownloader = new ImageDownloader(); context = MainActivity.this; } /** * 點選事件 */ private void initOnclick() { button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 獲取圖片 getBitmap(); } }); } /** * 顯示網路上拿到的圖片 */ private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: Bitmap bitmap = (Bitmap) msg.obj; imageView.setImageBitmap(bitmap); break; } } }; /** * 先從記憶體快取中拿圖片 * 如果沒有,網路獲取 */ public void getBitmap() { Bitmap bitmap = imageDownloader.getBitmapFromMemCache("bitmap"); if (bitmap == null) { httpPicture("http://img4.imgtn.bdimg.com/it/u=1210092829,3173610289&fm=11&gp=0.jpg"); Logger.t("111").d("網路獲取"); } else { imageView.setImageBitmap(bitmap); Logger.t("111").d("記憶體快取中獲取"); } } /** * 開執行緒訪問網路 * * @param bitmapUrl */ private void httpPicture(final String bitmapUrl) { new Thread() { @Override public void run() { Log.i("111", "run: " + Thread.currentThread().getName()); Bitmap bitmap = null; HttpURLConnection connection = null; InputStream inputStream = null; try { URL url = new URL(bitmapUrl); connection = (HttpURLConnection) url.openConnection(); connection.setConnectTimeout(5000); connection.setRequestMethod("GET"); if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) { inputStream = connection.getInputStream(); bitmap = BitmapFactory.decodeStream(inputStream); } // 儲存圖片 imageDownloader.addBitmapToMemory("bitmap", bitmap); // 顯示圖片 Message message = handler.obtainMessage(); message.obj = bitmap; message.what = 1; handler.sendMessage(message); } catch (Exception e) { e.printStackTrace(); } finally { if (connection != null) { connection.disconnect(); } if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } }.start(); } }
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="顯示圖片"
/>
<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"/>