1. 程式人生 > >Android快取機制——LruCache在記憶體中快取

Android快取機制——LruCache在記憶體中快取

一、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"/>