android lruCache 缓存机制

原文

Android缓存机制-LRU cache原理与用法

在使用Android图片加载框架时,经常会提到三级缓存,其中主要的是内存缓存和文件缓存。 两个缓存都是用到了LruCache算法,在Android分别对应:LruCache和DiskLruCache。

  • IRU算法
    操作系统中进行内存管理中时采用一些页面置换算法,如LRU、LFU和FIFO等。
    其中LRU(Least recently used,最近最少使用)算法,核心思想是当缓存达到上限时,会先淘汰最近最少使用的缓存。这样可以保证缓存处于一种可控的状态,有效的防止OOM的出现。

LruCache用法

LruCache是从Android3.1开始支持,目前已经在androidx.collection支持。

初始化
LruCache初始化:

  val maxCache = (Runtime.getRuntime().maxMemory() / 1024).toInt()
    //初始化大小:内存的1/8
    val cacheSize = maxCache / 8
    var memorySize = object : LruCache<String, Bitmap>(512) {
        override fun sizeOf(key: String, value: Bitmap): Int {
            //重写该方法,计算每张要缓存的图片大小
            return value.byteCount / 1024
        }
    }

原文
一、 我们建立一个简单的项目去体会LruCache的使用过程
通过http请求网络上的图片文件,然后保存在缓存中。显示图片时,先从缓存中取,如果没有,就发送请求向服务器取。项目结构如下:

在这里插入图片描述

二、 在AndroidManifest.xml文件中,加入网络权限的声明:

<uses-permission android:name="android.permission.INTERNET"/>

三、 使用实例

  val maxCache = (Runtime.getRuntime().maxMemory() / 1024).toInt()
    //初始化大小:内存的1/8
    val cacheSize = maxCache / 8
    var lruCache = object : LruCache<String, Bitmap>(cacheSize) {
        override fun sizeOf(key: String, value: Bitmap): Int {
            //重写该方法,计算每张要缓存的图片大小
            return value.byteCount / 1024
        }
    }

    //获取图片
    fun HandleRequest(target: T) {
        try {
            val url = mRequestMap.get(target)
            if (url == null) {
                return
            }
            var bitmap: Bitmap? = null
            if (lruCache.get(url) === null) { // 如果缓存中没有就重新获取
                var bitmapBytes: ByteArray = FlickrFetchr().getUrlBytes(url)
                bitmap = BitmapFactory.decodeByteArray(bitmapBytes, 0, bitmapBytes.size)
                lruCache.put(url, bitmap)
            } else {
                bitmap = lruCache.get(url) //否则取出
            }
            Log.i(TAG, "bitmap created")
            mResponseHandler.post(object : Runnable { // 应为MResponseHanlder与主线程相关联,所以UI更新代码会在主程序中完成
                override fun run() {
                    if (mRequestMap.get(target) != url || mHasQuit) { // 检查target是否改变,和当前主线程是否销毁
                        return
                    }
                    mRequestMap.remove(target)//删除已完成下载的target
                    bitmap?.let { mThumbnailDownloadListener?.onThumbnailDownload(target, it) } // 发送bitmap给主线程
                }

            })
        } catch (ioe: IOException) {
            Log.e(TAG, "Error downloading image", ioe)
        }
    }

完整类

package com.example.apps.photogallery

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Handler
import android.os.HandlerThread
import android.os.Message
import android.util.Log
import androidx.collection.LruCache
import java.io.IOException
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentMap


class ThumbnailDownload<T> : HandlerThread {
    private var mHasQuit = false
    //用来存储对Handler的引用,这个Handler负责在ThumbnailDownload后台线程上管理下载请求消息队列
    private var mRequestHandler: Handler? = null
    private var mRequestMap: ConcurrentMap<T, String> = ConcurrentHashMap()//线程安全的map

    private var mResponseHandler: Handler
    private var mThumbnailDownloadListener: ThumbnailDownloadListener<T>? = null

    val maxCache = (Runtime.getRuntime().maxMemory() / 1024).toInt()
    //初始化大小:内存的1/8
    val cacheSize = maxCache / 8
    var lruCache = object : LruCache<String, Bitmap>(cacheSize) {
        override fun sizeOf(key: String, value: Bitmap): Int {
            //重写该方法,计算每张要缓存的图片大小
            return value.byteCount / 1024
        }
    }

    //获取图片
    fun HandleRequest(target: T) {
        try {
            val url = mRequestMap.get(target)
            if (url == null) {
                return
            }
            var bitmap: Bitmap? = null
            if (lruCache.get(url) === null) { // 如果缓存中没有就重新获取
                var bitmapBytes: ByteArray = FlickrFetchr().getUrlBytes(url)
                bitmap = BitmapFactory.decodeByteArray(bitmapBytes, 0, bitmapBytes.size)
                lruCache.put(url, bitmap)
            } else {
                bitmap = lruCache.get(url) //否则取出
            }
            Log.i(TAG, "bitmap created")
            mResponseHandler.post(object : Runnable { // 应为MResponseHanlder与主线程相关联,所以UI更新代码会在主程序中完成
                override fun run() {
                    if (mRequestMap.get(target) != url || mHasQuit) { // 检查target是否改变,和当前主线程是否销毁
                        return
                    }
                    mRequestMap.remove(target)//删除已完成下载的target
                    bitmap?.let { mThumbnailDownloadListener?.onThumbnailDownload(target, it) } // 发送bitmap给主线程
                }

            })
        } catch (ioe: IOException) {
            Log.e(TAG, "Error downloading image", ioe)
        }
    }

    constructor(response: Handler) : super(TAG) {
        this.mResponseHandler = response
    }

    public interface ThumbnailDownloadListener<T> {
        fun onThumbnailDownload(target: T, thumbnai: Bitmap);
    }

    public fun setThumbnailDownloadListener(listener: ThumbnailDownloadListener<T>) {
        mThumbnailDownloadListener = listener
    }

    override fun quit(): Boolean {
        mHasQuit = true
        return super.quit()
    }

    // onLooperPrepared在Looper首次检查消息队列之前调用,所以该方法是实现Handler的好地方
    override fun onLooperPrepared() {
        mRequestHandler = object : Handler() {
            override fun handleMessage(msg: Message) {
                if (msg.what == MESSAGE_DOWNLOAD) {
                    var target = msg.obj as T
                    Log.i(TAG, "Got a request for url: " + mRequestMap.get(target))
                    HandleRequest(target) //处理消息
                }

            }
        }
    }


    fun clearQueue() {
        mRequestHandler?.removeMessages(MESSAGE_DOWNLOAD)
        mRequestMap.clear()
    }

    fun queueThumbnail(target: T, url: String) {
        Log.i(TAG, "Got a URL: " + url)
        if (url === null) {
            mRequestMap.remove(target)
        } else {
            mRequestMap.put(target, url);
            mRequestHandler?.obtainMessage(MESSAGE_DOWNLOAD, target)
                ?.sendToTarget()//obtainMessage方法会从公共回收池里获取消息
        }
    }

    companion object {
        val TAG = "ThumbnailDownload"
        val MESSAGE_DOWNLOAD = 0 //用来标识下载请求消息,ThumbnailDownload会把它设为任何新创建消息的WHAT属性
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值