【Android 内存优化】Bitmap 内存缓存 ( Bitmap 缓存策略 | LruCache 内存缓存 | LruCache 常用操作 | 工具类代码 )

简介: 【Android 内存优化】Bitmap 内存缓存 ( Bitmap 缓存策略 | LruCache 内存缓存 | LruCache 常用操作 | 工具类代码 )

文章目录

一、Bitmap 内存缓存策略

二、LruCache 内存缓存

三、LruCache 常用操作

四、LruCache 工具类

五、源码及资源下载



官方参考 : Google 官方提供的 内存优化参考 ;


Glide 开源库 : 官方建议凡是使用到 Bitmap 解码 , 显示 , 缓存等操作 , 直接使用 Glide 开源库进行上述操作 , 不建议直接操作 Bitmap 对象 ;






一、Bitmap 内存缓存策略


1 . Android 2.3.3(API 级别 10)及以下的版本中 , 使用 Bitmap 对象的 recycle 方法回收内存 ;




2 . Android 3.0(API 级别 11)及以上的版本中 , 使用新引入的 Bitmap 内存复用机制 , 通过设置 BitmapFactory.Options.inBitmap 字段 , 图像解码时 , 会尝试复用该设置的 inBitmap 内存 , 该内存复用有以下限制 :



① Android 4.4(API 级别 19)及以上的版本 : 在 Android 4.4(API 级别 19)及以上的版本中 , 只要被解码后的 Bitmap 对象的字节大小 , 小于等于 inBitmap 的字节大小 , 就可以复用成功 ; 解码后的乳香可以是缩小后的 , 即 BitmapFactory.Options.inSampleSize 可以大于1 ;


② Android 4.4(API 级别 19)以下的版本 : 在 Android 4.4(API 级别 19) 之前的代码中 , 复用的前提是必须同时满足以下 3 33 个条件 :


被解码的图像必须是 JPEG 或 PNG 格式

被复用的图像宽高必须等于 解码后的图像宽高

解码图像的 BitmapFactory.Options.inSampleSize 设置为 1 , 也就是不能缩放

才能复用成功 , 另外被复用的图像的像素格式 Config ( 如 RGB_565 ) 会覆盖设置的 BitmapFactory.Options.inPreferredConfig 参数 ;






二、LruCache 内存缓存


1 . LruCache 简介 : 内存缓存一般使用 LruCache , 在 【Android 应用开发】LruCache 简介 博客中有简要介绍 ;



① LRU 算法 : LruCache 使用 LRU ( Least Recently Used 最近最少使用 ) 算法 , 其内部维护了一个 LinkedHashMap 队列 ;


② LRU 数据淘汰原理 : 最近最少使用的数据 , 将会被淘汰 ;


③ LRU 缓存数据优先级 : 如果某数据最近被访问过 , 那么之后的一段时间可能被访问的几率增加 , 其优先级提高 , 如果某数据很长时间没有访问 , 其优先级会被降低 ; 当 LruCache 缓存的内存数据达到了设定的缓存大小 , 低优先级的数据会被先淘汰 ;




2 . 数据结构 : 该队列使用双向链表实现 , 实际存放内存数据的是 LinkedHashMap 集合 ;


// 这是定义杂 LruCache 中的内部集合
private final LinkedHashMap<K, V> map;



3 . LruCache 工作机制 :



① 获取数据时 :


有缓存 : 如果 LinkedHashMap 缓存中存在该 key 对应的数据 , 那么直接返回该数据 , 并且将该数据放到队头 ;


没有缓存 : 如果 LinkedHashMap 缓存中不存在该 key 对应的数据 , 那么需要创建该数据 , 并插入到 LinkedHashMap 中 , 并且返回该数据 ;



② 插入数据处理 :


缓存没有满 : 向 LinkedHashMap 插入数据 , 如果缓存没有满 , 直接将该数据插入到队头 ;

缓存满了 : 向 LinkedHashMap 插入数据 , 如果缓存满了, 将队尾的若干数据移除队列 , 然后将新数据插入到队头 ;



Lru 内存 缓存 , Disk 磁盘缓存参考 : JakeWharton/DiskLruCache






三、LruCache 常用操作


1 . 创建 LruCache :



① 指定内存 : 创建 LruCache 时 , 需要指定该缓存的最大内存 , 一般是 APP 可用内存的 1/8 ;


② 实现移除回调方法 : 由于内存紧张 , LruCache 将队尾的数据移除队列 , 会回调 entryRemoved , 可以进行一些用户自定义的处理 ;


   

// 设置的内存 , 一般是 APP 可用内存的 1/8
        LruCache<String, Bitmap> mLruCache = new LruCache<String, Bitmap>(lruCacheMemoryByte){
            /**
             * 返回 LruCache 的键和值的大小 , 单位使用用户自定义的单位
             * 默认的实现中 , 返回 1 ; size 是 键值对个数 , 最大的 size 大小是最多键值对个数
             * 键值对条目在 LruCache 中缓存时 , 其大小不能改变
             * @param key
             * @param value
             * @return 返回 LruCache<String, Bitmap> 的值 , 即 Bitmap 占用内存
             */
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getByteCount();
            }
            /**
             * 从 LruCache 缓存移除 Bitmap 时会回调该方法
             * @param evicted
             * @param key
             * @param oldValue
             * @param newValue
             */
            @Override
            protected void entryRemoved(boolean evicted, String key, Bitmap oldValue,
                                        Bitmap newValue) {
                super.entryRemoved(evicted, key, oldValue, newValue);
                oldValue.recycle();
            }
        };



2 . LruCache 操作 :



① 存放数据 : mLruCache.put(key, value) ;


② 取出数据 : mLruCache.get(key) ;


③ 清除所有缓存数据 : mLruCache.evictAll() ;






四、LruCache 工具类


LruCache 缓存 Bitmap 工具类 :


package kim.hsl.bm.utils;


import android.app.ActivityManager;

import android.content.Context;

import android.graphics.Bitmap;

import android.util.LruCache;


/**
 * Bitmap 内存缓存
 * 单纯使用 LruCache 缓存图片到内存中
 */
public class BitmapLruCache {
    private static final String TAG = "BitmapMemoryCache";
    /**
     * 应用上下文对象
     */
    private Context mContext;
    /**
     * 缓存图片的 LruCache
     */
    private LruCache<String, Bitmap> mLruCache;
    /**
     * 单例实现
     */
    private static BitmapLruCache INSTANCE;
    private BitmapLruCache(){}
    public static BitmapLruCache getInstance(){
        if(INSTANCE == null){
            INSTANCE = new BitmapLruCache();
        }
        return INSTANCE;
    }
    /**
     * 使用时初始化
     * @param context
     */
    public void init(Context context){
        // 初始化内存缓存
        initLruCache(context);
    }
    /**
     * 不使用时释放
     */
    public void release(){
    }
    private void initLruCache(Context context){
        // 为成员变量赋值
        this.mContext = context;
        // 获取 Activity 管理器
        ActivityManager activityManager = (ActivityManager) context.getSystemService(
                Context.ACTIVITY_SERVICE);
        // 获取应用可用的最大内存
        int maxMemory = activityManager.getMemoryClass();
        // 获取的 maxMemory 单位是 MB , 将其转为字节 , 除以 8
        int lruCacheMemoryByte = maxMemory / 8 * 1024 * 1024;
        // 设置的内存 , 一般是 APP 可用内存的 1/8
        mLruCache = new LruCache<String, Bitmap>(lruCacheMemoryByte){
            /**
             * 返回 LruCache 的键和值的大小 , 单位使用用户自定义的单位
             * 默认的实现中 , 返回 1 ; size 是 键值对个数 , 最大的 size 大小是最多键值对个数
             * 键值对条目在 LruCache 中缓存时 , 其大小不能改变
             * @param key
             * @param value
             * @return 返回 LruCache<String, Bitmap> 的值 , 即 Bitmap 占用内存
             */
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getByteCount();
            }
            /**
             * 从 LruCache 缓存移除 Bitmap 时会回调该方法
             * @param evicted
             * @param key
             * @param oldValue
             * @param newValue
             */
            @Override
            protected void entryRemoved(boolean evicted, String key, Bitmap oldValue,
                                        Bitmap newValue) {
                super.entryRemoved(evicted, key, oldValue, newValue);
                oldValue.recycle();
            }
        };
    }
    /*
        下面的 3 个方法是提供给用户用于操作 LruCache 的接口
     */
    /**
     * 将键值对放入 LruCache 中
     * @param key
     * @param value
     */
    public void putBitmapToLruCache(String key, Bitmap value){
        mLruCache.put(key, value);
    }
    /**
     * 从 LruCache 中获取 Bitmap 对象
     * @param key
     * @return
     */
    public Bitmap getBitmapFromLruCache(String key){
        return mLruCache.get(key);
    }
    /**
     * 清除 LruCache 缓存
     */
    public void clearLruCache(){
        mLruCache.evictAll();
    }
}





五、源码及资源下载


源码及资源下载地址 :


① GitHub 工程地址 : BitmapMemory


② BitmapLruCache.java 工具类地址 : BitmapLruCache.java


目录
相关文章
|
3月前
|
存储 分布式计算 监控
阿里云服务器实例经济型e、通用算力型u1、计算型c8i、通用型g8i、内存型r8i详解与选择策略
在阿里云现在的活动中,可选的云服务器实例规格主要有经济型e、通用算力型u1、计算型c8i、通用型g8i、内存型r8i实例,虽然阿里云在活动中提供了多种不同规格的云服务器实例,以满足不同用户和应用场景的需求。但是有的用户并不清楚他们的性能如何,应该如何选择。本文将详细介绍阿里云服务器中的经济型e、通用算力型u1、计算型c8i、通用型g8i、内存型r8i实例的性能、适用场景及选择参考,帮助用户根据自身需求做出更加精准的选择。
|
13天前
|
存储 缓存
.NET 6中Startup.cs文件注入本地缓存策略与服务生命周期管理实践:AddTransient, AddScoped, AddSingleton。
记住,选择正确的服务生命周期并妥善管理它们是至关重要的,因为它们直接影响你的应用程序的性能和行为。就像一个成功的建筑工地,工具箱如果整理得当,工具选择和使用得当,工地的整体效率将会大大提高。
42 0
|
1月前
|
缓存 搜索推荐 CDN
HTTP缓存策略的区别和解决的问题
总的来说,HTTP缓存策略是一种权衡,需要根据具体的应用场景和需求来选择合适的策略。理解和掌握这些策略,可以帮助我们更好地优化网页性能,提高用户的浏览体验。
56 11
|
3月前
|
数据采集 缓存 JavaScript
数据抓取的缓存策略:减少重复请求与资源消耗
本教程聚焦于提升爬虫效率与稳定性,通过结合缓存策略、代理IP技术(如爬虫代理)、Cookie和User-Agent设置,优化数据采集流程。以知乎为例,详细讲解如何抓取指定关键词的文章标题和内容。内容涵盖环境准备、代码实现、常见问题及解决方案,并提供延伸练习,帮助读者掌握高效爬虫技巧。适合具备Python基础的初学者,助你规避网站机制,顺利获取目标数据。
104 2
数据抓取的缓存策略:减少重复请求与资源消耗
|
3月前
|
缓存 监控 算法
JVM简介—2.垃圾回收器和内存分配策略
本文介绍了Java垃圾回收机制的多个方面,包括垃圾回收概述、对象存活判断、引用类型介绍、垃圾收集算法、垃圾收集器设计、具体垃圾回收器详情、Stop The World现象、内存分配与回收策略、新生代配置演示、内存泄漏和溢出问题以及JDK提供的相关工具。
JVM简介—2.垃圾回收器和内存分配策略
|
3月前
|
机器学习/深度学习 存储 PyTorch
PyTorch内存优化的10种策略总结:在有限资源环境下高效训练模型
在大规模深度学习模型训练中,GPU内存容量常成为瓶颈,特别是在训练大型语言模型和视觉Transformer时。本文系统介绍了多种内存优化策略,包括混合精度训练、低精度训练(如BF16)、梯度检查点、梯度累积、张量分片与分布式训练、
121 14
PyTorch内存优化的10种策略总结:在有限资源环境下高效训练模型
|
4月前
|
机器学习/深度学习 计算机视觉
RT-DETR改进策略【卷积层】| CVPR-2023 部分卷积 PConv 轻量化卷积,降低内存占用
RT-DETR改进策略【卷积层】| CVPR-2023 部分卷积 PConv 轻量化卷积,降低内存占用
153 13
RT-DETR改进策略【卷积层】| CVPR-2023 部分卷积 PConv 轻量化卷积,降低内存占用
|
4月前
|
机器学习/深度学习 编解码 BI
YOLOv11改进策略【Conv和Transformer】| CVPR-2023 BiFormer 稀疏自注意力,减少内存占用
YOLOv11改进策略【Conv和Transformer】| CVPR-2023 BiFormer 稀疏自注意力,减少内存占用
180 3
YOLOv11改进策略【Conv和Transformer】| CVPR-2023 BiFormer 稀疏自注意力,减少内存占用
|
4月前
|
机器学习/深度学习 编解码 BI
RT-DETR改进策略【Conv和Transformer】| CVPR-2023 BiFormer 稀疏自注意力,减少内存占用
RT-DETR改进策略【Conv和Transformer】| CVPR-2023 BiFormer 稀疏自注意力,减少内存占用
113 0
RT-DETR改进策略【Conv和Transformer】| CVPR-2023 BiFormer 稀疏自注意力,减少内存占用
|
4月前
|
机器学习/深度学习 计算机视觉
YOLOv11改进策略【卷积层】| CVPR-2023 部分卷积 PConv 轻量化卷积,降低内存占用
YOLOv11改进策略【卷积层】| CVPR-2023 部分卷积 PConv 轻量化卷积,降低内存占用
315 0
YOLOv11改进策略【卷积层】| CVPR-2023 部分卷积 PConv 轻量化卷积,降低内存占用

热门文章

最新文章

下一篇
oss创建bucket