【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


目录
相关文章
|
22天前
|
缓存 监控 Android开发
安卓应用性能优化的实用策略
【4月更文挑战第2天】 在竞争激烈的应用市场中,一款应用的性能直接影响用户体验和市场表现。本文针对安卓平台,深入探讨了性能优化的关键要素,包括内存管理、代码效率、UI渲染和电池使用效率。通过分析常见的性能瓶颈,并提供针对性的解决策略,旨在帮助开发者构建更加流畅、高效的安卓应用。
|
1月前
|
编解码 算法 Java
构建高效的Android应用:内存优化策略详解
随着智能手机在日常生活和工作中的普及,用户对移动应用的性能要求越来越高。特别是对于Android开发者来说,理解并实践内存优化是提升应用程序性能的关键步骤。本文将深入探讨针对Android平台的内存管理机制,并提供一系列实用的内存优化技巧,以帮助开发者减少内存消耗,避免常见的内存泄漏问题,并确保应用的流畅运行。
|
1月前
|
缓存 移动开发 Android开发
提升安卓应用性能的实用策略
在移动开发领域,应用的性能优化是一个持续的挑战。对于安卓开发者而言,确保应用流畅、快速并且电池使用效率高,是吸引和保持用户的关键因素之一。本文将深入探讨针对安卓平台的性能优化技巧,包括内存管理、代码效率、UI渲染以及电池寿命等方面的考量。这些策略旨在帮助开发者构建出更高效、响应更快且用户体验更佳的安卓应用。
|
7天前
|
移动开发 Android开发 开发者
构建高效Android应用:采用Kotlin进行内存优化的策略
【4月更文挑战第18天】 在移动开发领域,性能优化一直是开发者关注的焦点。特别是对于Android应用而言,由于设备和版本的多样性,确保应用流畅运行且占用资源少是一大挑战。本文将探讨使用Kotlin语言开发Android应用时,如何通过内存优化来提升应用性能。我们将从减少不必要的对象创建、合理使用数据结构、避免内存泄漏等方面入手,提供实用的代码示例和最佳实践,帮助开发者构建更加高效的Android应用。
11 0
|
8天前
|
缓存 移动开发 Java
构建高效的Android应用:内存优化策略
【4月更文挑战第16天】 在移动开发领域,尤其是针对资源有限的Android设备,内存优化是提升应用性能和用户体验的关键因素。本文将深入探讨Android应用的内存管理机制,分析常见的内存泄漏问题,并提出一系列实用的内存优化技巧。通过这些策略的实施,开发者可以显著减少应用的内存占用,避免不必要的后台服务,以及提高垃圾回收效率,从而延长设备的电池寿命并确保应用的流畅运行。
|
11天前
|
编解码 人工智能 测试技术
安卓适配性策略:确保应用在不同设备上的兼容性
【4月更文挑战第13天】本文探讨了提升安卓应用兼容性的策略,包括理解平台碎片化、设计响应式UI(使用dp单位,考虑横竖屏)、利用Android SDK的兼容工具(支持库、资源限定符)、编写兼容性代码(运行时权限、设备特性检查)以及优化性能以适应低端设备。适配性是安卓开发的关键,通过这些方法可确保应用在多样化设备上提供一致体验。未来,自动化测试和AI将助力应对设备碎片化挑战。
|
28天前
|
缓存 Java Android开发
安卓应用开发中的内存优化策略
在移动应用开发领域,性能一直是衡量应用质量的重要指标之一。特别是对于安卓平台,由于设备的硬件配置多样化,内存管理成为开发者面临的重大挑战。本文将深入探讨针对安卓平台的内存优化技巧,包括内存泄漏的预防、合理使用数据结构和算法、以及高效的资源释放机制。通过这些方法,开发者可以显著提升应用的性能和用户体验。
|
1月前
|
缓存 移动开发 Java
构建高效Android应用:内存优化实战指南
在移动开发领域,性能优化是提升用户体验的关键因素之一。特别是对于Android应用而言,由于设备和版本的多样性,内存管理成为开发者面临的一大挑战。本文将深入探讨Android内存优化的策略和技术,包括内存泄漏的诊断与解决、合理的数据结构选择、以及有效的资源释放机制。通过实际案例分析,我们旨在为开发者提供一套实用的内存优化工具和方法,以构建更加流畅和高效的Android应用。
|
1月前
|
监控 Java Android开发
构建高效Android应用:从内存管理到性能优化
【2月更文挑战第30天】 在移动开发领域,打造一个流畅且响应迅速的Android应用是每个开发者追求的目标。本文将深入探讨如何通过有效的内存管理和细致的性能调优来提升应用效率。我们将从分析内存泄露的根本原因出发,讨论垃圾回收机制,并探索多种内存优化策略。接着,文中将介绍多线程编程的最佳实践和UI渲染的关键技巧。最后,我们将通过一系列实用的性能测试工具和方法,帮助开发者监控、定位并解决性能瓶颈。这些技术的综合运用,将指导读者构建出更快速、更稳定、用户体验更佳的Android应用。
|
1月前
|
存储 JSON 监控
Higress Controller**不是将配置信息推送到Istio的内存存储里面的**。
【2月更文挑战第30天】Higress Controller**不是将配置信息推送到Istio的内存存储里面的**。
14 1