文章目录

  • 一、Google 官方 Bitmap 相关示例参考
  • 二、磁盘缓存类 DiskLruCache
  • 三、磁盘缓存初始化
  • 四、存储数据到磁盘缓存中
  • 五、从磁盘缓存中读取数据
  • 六、 Android 10 文件访问
  • 七、代码示例
    • 1、二级缓存代码示例
    • 2、调用工具类代码示例
  • 八、源码及资源下载

在上一篇博客 【Android 内存优化】Bitmap 内存缓存 ( Bitmap 内存复用 | 弱引用 | 引用队列 | 针对不同 Android 版本开发不同的 Bitmap 复用策略 | 工具类代码 ) 中 , 使用 LruCache 缓存内存数据 , 同时兼顾 Bitmap 内存复用 , 使用弱引用 Bitmap 对象集合维护 Bitmap 复用池 , 确保该复用池中的 Bitmap 对象寿命都很短 , 每次 GC 都会清理一遍复用池 ; 当 LruCache 中的数据由于最近不常使用 , 从 LruCache 内存中移除 , 此时将其放入 Bitmap 复用池中 , 将该 Bitmap 对象纳入复用机制管理 ;

一、Google 官方 Bitmap 相关示例参考


Google 官方相关示例参考 :

① Android 官方示例 : https://github.com/android

② Android 图形示例 : android/graphics-samples

③ Bitmap 展示 Module : DisplayingBitmaps

④ 官方示例中的硬盘缓存类 : DiskLruCache.java

在 DisplayingBitmaps 示例中 , Google 官方展示了在应用中如何使用 Bitmap ;

二、磁盘缓存类 DiskLruCache


推荐使用 JakeWharton 的开源库 DiskLruCache , 点击上述连接即可进入工程界面 ;

点击 GitHub 界面右侧的 Release 界面 , 下载发布的 Release 版本 , 尽量不要直接下载开发中的最新版本 ;

这里选择下载最新的 Release 版本 , disklrucache-2.0.2 版本 , 点击此处直接调转到该界面 ;

下载完毕后 , 打开压缩包 , 直接将这三个文件 , 拷贝到项目中 ;

三、磁盘缓存初始化


首先声明 DiskLruCache 磁盘 LRU 缓存类 ,然后初始化 DiskLruCache 类 , 主要是设置磁盘缓存目录 , 应用版本号 , 每个 Key 可以对应多个文件个数 , 磁盘大小

    /*** 磁盘缓存*/private DiskLruCache mDiskLruCache;/*** 初始化磁盘缓存* @param diskDirectory*/private void initDiskLruCache(String diskDirectory){try {/*初始化内存缓存需要传入内存缓存目录文件APP 版本缓存值的个数缓存大小 , 单位字节 , 这个最重要*/mDiskLruCache = DiskLruCache.open(new File(diskDirectory),BuildConfig.VERSION_CODE,1,8 * 1024 * 10024);} catch (IOException e) {e.printStackTrace();}}

四、存储数据到磁盘缓存中


1 . 从 DiskLruCache 中获取 Bitmap 流程 :

① 获取快照 : 通过 key 获取 DiskLruCache.Snapshot 对象 ;

snapshot = mDiskLruCache.get(key);

② 打开编辑器 : 打开 DiskLruCache.Editor , 该用法与 SharedPreference 用法类似 ;

DiskLruCache.Editor editor = mDiskLruCache.edit(key);

③ 获取输出流 : 从 DiskLruCache.Editor 对象中获取出输出流 , 这里的 0 表示获取该 key 对应的第 0 个文件 , 每个 Key 可以对应多个文件 , 这个值是创建 DiskLruCache 时传入的 valueCount 参数 ;

outputStream = editor.newOutputStream(0);

④ 写出 Bitmap 对象到文件中 :

bitmap.compress(Bitmap.CompressFormat.JPEG, 0, outputStream);

⑤ 编辑器提交数据 :

editor.commit();

2 . 代码示例 :

    /*** 将 Bitmap 放入 磁盘缓存 中* @param key* @param bitmap*/public void putBitmapToDisk(String key, Bitmap bitmap){DiskLruCache.Snapshot snapshot = null;OutputStream outputStream = null;try {snapshot = mDiskLruCache.get(key);// 如果缓存中有对应 key 键值的文件 , 不进行任何处理if(snapshot != null) {// 该用法与 SharedPreference 用法类似DiskLruCache.Editor editor = mDiskLruCache.edit(key);if(editor != null){// 这里的 0 表示获取该 key 对应的第 0 个文件// 每个 可以 可以对应多个文件 , 这个值是创建 DiskLruCache 时传入的 valueCount 参数outputStream = editor.newOutputStream(0);// 写出 Bitmap 对象到文件中bitmap.compress(Bitmap.CompressFormat.JPEG, 0, outputStream);// 该用法与 SharedPreference 用法类似editor.commit();}}} catch (IOException e) {e.printStackTrace();}finally {if(snapshot != null) {snapshot.close();}if(outputStream != null){try {outputStream.close();} catch (IOException e) {e.printStackTrace();}}}}

五、从磁盘缓存中读取数据


1 . 从 DiskLruCache 中获取 Bitmap 流程 :

① 获取快照 : 通过 key 获取 DiskLruCache.Snapshot 对象 ;

snapshot = mDiskLruCache.get(key);

② 打开编辑器 : 打开 DiskLruCache.Editor , 该用法与 SharedPreference 用法类似 ;

DiskLruCache.Editor editor = mDiskLruCache.edit(key);

③ 获取输入流 : 从 DiskLruCache.Editor 对象中获取出输入流 , 这里的 0 表示获取该 key 对应的第 0 个文件 , 每个 Key 可以对应多个文件 , 这个值是创建 DiskLruCache 时传入的 valueCount 参数 ;

inputStream = editor.newInputStream(0);

④ 从输入流中读取数据到 Bitmap 中 : 这里用到了 Bitmap 内存复用机制 , 另外从磁盘读取数据后 , 向内存缓存一份 ;

                    BitmapFactory.Options options = new BitmapFactory.Options();options.inMutable = true;options.inBitmap = inBitmap;// 写出 Bitmap 对象到文件中bitmap = BitmapFactory.decodeStream(inputStream, null, options);if(bitmap != null){// 从磁盘读取后 , 先缓存到内存中mLruCache.put(key, bitmap);}

⑤ 编辑器提交数据 :

editor.commit();

2 . 代码示例 :

    /*** 从 磁盘缓存 中取出 Bitmap 对象* @param key       键值* @param inBitmap 复用 Bitmap 内存* @return*/public Bitmap getBitmapFromDisk(String key, Bitmap inBitmap){Bitmap bitmap = null;DiskLruCache.Snapshot snapshot = null;InputStream inputStream = null;try {snapshot = mDiskLruCache.get(key);// 如果缓存中有对应 key 键值的文件 , 不进行任何处理if(snapshot != null) {// 该用法与 SharedPreference 用法类似DiskLruCache.Editor editor = mDiskLruCache.edit(key);if(editor != null){// 这里的 0 表示获取该 key 对应的第 0 个文件// 每个 可以 可以对应多个文件 , 这个值是创建 DiskLruCache 时传入的 valueCount 参数inputStream = editor.newInputStream(0);BitmapFactory.Options options = new BitmapFactory.Options();options.inMutable = true;options.inBitmap = inBitmap;// 写出 Bitmap 对象到文件中bitmap = BitmapFactory.decodeStream(inputStream, null, options);if(bitmap != null){// 从磁盘读取后 , 先缓存到内存中mLruCache.put(key, bitmap);}// 该用法与 SharedPreference 用法类似editor.commit();}}} catch (IOException e) {e.printStackTrace();}finally {if(snapshot != null) {snapshot.close();}if(inputStream != null){try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}}return bitmap;}

六、 Android 10 文件访问


文件存储相关官方参考资料 :

  • Android 11 中的存储机制更新
  • Android storage use cases and best practices
  • 应用数据和文件

参考之前的博客 【Android 内存优化】Android 原生 API 图片压缩代码示例 ( PNG 格式压缩 | JPEG 格式压缩 | WEBP 格式压缩 | 动态权限申请 | Android10 存储策略 ) 三、 Android 10 文件访问 有涉及到在 Android 10 系统中访问 SD 卡 ;

七、代码示例


1、二级缓存代码示例


磁盘内存二级缓存代码示例 :

package kim.hsl.bm.utils;import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.util.LruCache;import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;import kim.hsl.bm.BuildConfig;
import kim.hsl.bm.diskcache.DiskLruCache;/*** Bitmap 内存缓存* 在将图片缓存到 LruCache 内存中基础上 ,* 将从 LruCache 中移除的最近没有使用的 Bitmap 对象的内存复用* 这样能最大限度减少内存抖动*/
public class BitmapDiskLruCacheMemoryReuse {private static final String TAG = "BitmapMemoryCache";/*** 应用上下文对象*/private Context mContext;/*** 缓存图片的 LruCache*/private LruCache<String, Bitmap> mLruCache;/*** 磁盘缓存*/private DiskLruCache mDiskLruCache;/*** Bitmap 复用池* 使用 inBitmap 复用选项* 需要获取图片时 , 优先从 Bitmap 复用池中查找* 这里使用弱引用保存该 Bitmap , 每次 GC 时都会回收该 Bitmap* 创建一个线程安全的 HashSet , 其中的元素是 Bitmap 弱引用** 该 Bitmap 复用池的作用是 , 假如 Bitmap 对象长时间不使用 , 就会从内存缓存中移除** Bitmap 回收策略 :* 3.0 以下系统中 , Bitmap 内存在 Native 层* 3.0 以上系统中 , Bitmap 内存在 Java 层* 8.0 及以上的系统中 , Bitmap 内存在 Native 层** 因此这里需要处理 Bitmap 内存在 Native 层的情况 , 监控到 Java 层的弱引用被释放了* 需要调用 Bitmap 对象的 recycle 方法 , 释放 Native 层的内存** 需要使用引用队列监控弱引用的释放情况*/Set<WeakReference<Bitmap>> bitmapReusePool;/*** 引用队列 , 用于监控 Set<WeakReference<Bitmap>> bitmapReusePool 的内存是否被回收* 需要维护一个线程 , 不断尝试从该引用队列中获取引用**/private ReferenceQueue<Bitmap> referenceQueue;/*** 监控 Set<WeakReference<Bitmap>> bitmapReusePool 的内存是否被回收 ,* 调用 ReferenceQueue<Bitmap> referenceQueue 的 remove 方法 ,* 查看是否存在被回收的弱引用 , 如果存在 , 直接回收该弱引用对应的 Bitmap 对象*/private Thread referenceQueueMonitorThread;/*** 是否持续监控引用队列 ReferenceQueue*/private boolean isMonitorReferenceQueue = true;/*** 单例实现*/private static BitmapDiskLruCacheMemoryReuse INSTANCE;private BitmapDiskLruCacheMemoryReuse(){}public static BitmapDiskLruCacheMemoryReuse getInstance(){if(INSTANCE == null){INSTANCE = new BitmapDiskLruCacheMemoryReuse();}return INSTANCE;}/*** 使用时初始化* @param context*/public void init(Context context, String diskDirectory){// 初始化内存缓存initLruCache(context);// 初始化弱引用队列initBitmapReusePool();// 初始化磁盘缓存initDiskLruCache(diskDirectory);}/*** 不使用时释放*/public void release(){isMonitorReferenceQueue = false;}private void initLruCache(Context context){// 为成员变量赋值this.mContext = context;// 获取 Activity 管理器ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);// 获取应用可用的最大内存int maxMemory = activityManager.getMemoryClass();// 获取的 maxMemory 单位是 MB , 将其转为字节 , 除以 8int lruCacheMemoryByte = maxMemory / 8 * 1024 * 1024;// 设置的内存 , 一般是 APP 可用内存的 1/8mLruCache = new LruCache<String, Bitmap>(lruCacheMemoryByte){/*** 返回 LruCache 的键和值的大小 , 单位使用用户自定义的单位* 默认的实现中 , 返回 1 ; size 是 键值对个数 , 最大的 size 大小是最多键值对个数* 键值对条目在 LruCache 中缓存时 , 其大小不能改变* @param key* @param value* @return 返回 LruCache<String, Bitmap> 的值 , 即 Bitmap 占用内存*/@Overrideprotected int sizeOf(String key, Bitmap value) {// 如果使用的是复用的 Bitmap 对象 , 其占用内存大小是之前的图像分配的内存大小// 大于等于当前图像的内存占用大小if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {return value.getAllocationByteCount();}return value.getByteCount();}/*** 从 LruCache 缓存移除 Bitmap 时会回调该方法* @param evicted* @param key* @param oldValue* @param newValue*/@Overrideprotected void entryRemoved(boolean evicted, String key, Bitmap oldValue,Bitmap newValue) {super.entryRemoved(evicted, key, oldValue, newValue);/*如果从 LruCache 内存缓存中移除的 Bitmap 是可变的才能被复用 , 否则只能回收该 Bitmap 对象Bitmap 回收策略 :3.0 以下系统中 , Bitmap 内存在 Native 层3.0 以上系统中 , Bitmap 内存在 Java 层8.0 及以上的系统中 , Bitmap 内存在 Native 层因此这里需要处理 Bitmap 内存在 Native 层的情况 , 监控到 Java 层的弱引用被释放了需要调用 Bitmap 对象的 recycle 方法 , 释放 Native 层的内存*/if(oldValue.isMutable()){   // 可以被复用// 将其放入弱引用中 , 每次 GC 启动后 , 如果该弱引用没有被使用 , 都会被回收bitmapReusePool.add(new WeakReference<Bitmap>(oldValue, referenceQueue));}else{  // 不可被复用 , 直接回收oldValue.recycle();}}};}/*** 初始化引用队列*/private void initBitmapReusePool(){// 创建一个线程安全的 HashSet , 其中的元素是 Bitmap 弱引用bitmapReusePool = Collections.synchronizedSet(new HashSet<WeakReference<Bitmap>>());// 引用队列 , 当弱引用被 GC 扫描后 , 需要回收 , 会将该弱引用放入队列// 一直不断的尝试从该引用队列中获取数据 , 如果获取到数据 , 就要回收该对象referenceQueue = new ReferenceQueue<>();// 定义监控线程referenceQueueMonitorThread = new Thread(){@Overridepublic void run() {while (isMonitorReferenceQueue){try {Reference<Bitmap> reference = (Reference<Bitmap>) referenceQueue.remove();Bitmap bitmap = reference.get();// 不为空 , 且没有被回收 , 回收 Bitmap 内存if(bitmap != null && !bitmap.isRecycled()){bitmap.recycle();}} catch (InterruptedException e) {e.printStackTrace();}}}};// 启动引用队列监控线程referenceQueueMonitorThread.start();}/*** 初始化磁盘缓存* @param diskDirectory*/private void initDiskLruCache(String diskDirectory){try {/*初始化内存缓存需要传入内存缓存目录文件APP 版本缓存值的个数缓存大小 , 单位字节 , 这个最重要*/mDiskLruCache = DiskLruCache.open(new File(diskDirectory),BuildConfig.VERSION_CODE,1,8 * 1024 * 10024);} catch (IOException e) {e.printStackTrace();}}/*** 获取一个可以被复用的 Bitmap 对象** 与 BitmapFactory 配合使用 :** Android 4.4 以后的 Bitmap 复用情况 :* 在 KITKAT ( Android 4.4 , 19 平台 ) 以后的代码中 ,* 只要被解码生成的 Bitmap 对象的字节大小 ( 缩放后的 )* 小于等于 inBitmap 的字节大小 , 就可以复用成功 ;** Android 4.4 之前的 Bitmap 复用情况 : ( 比较苛刻 )* 在 KITKAT 之前的代码中 , 被解码的图像必须是*  - JPEG 或 PNG 格式 ,*  - 并且 图像大小必须是相等的 ,*  - inssampleSize 设置为 1 ,* 才能复用成功 ;* 另外被复用的图像的 像素格式 Config ( 如 RGB_565 ) 会覆盖设置的 inPreferredConfig 参数** @param width* @param height* @param inSampleSize* @return*/public Bitmap getReuseBitmap(int width,int height,int inSampleSize){// Android 2.3.3(API 级别 10)及以下的版本中 , 使用 Bitmap 对象的 recycle 方法回收内存if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1){// 如果 API 级别小于等于 10 , 不启用 Bitmap 内存复用机制 , 返回 null 即可return null;}// 获取准备复用的 Bitmap , 之后设置到 Options 中Bitmap inBitmap = null;// 使用迭代器遍历该 Set 集合 , 如果遍历中涉及到删除 , 就要使用迭代器遍历Iterator<WeakReference<Bitmap>> iterator = bitmapReusePool.iterator();//迭代查找符合复用条件的Bitmapwhile (iterator.hasNext()){// 循环遍历 Bitmap 对象Bitmap bitmap = iterator.next().get();if (bitmap != null){/*检查该 Bitmap 对象是否可以达到复用要求 ,如果达到复用要求 , 就取出这个 Bitmap 对象 , 并将其从队列中移除*/if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR2){/*Android 4.4(API 级别 19)以下的版本 : 在 Android 4.4(API 级别 19) 之前的代码中 ,复用的前提是必须同时满足以下 3 个条件 :1. 被解码的图像必须是 JPEG 或 PNG 格式2. 被复用的图像宽高必须等于 解码后的图像宽高3. 解码图像的 BitmapFactory.Options.inSampleSize 设置为 1 , 也就是不能缩放才能复用成功 , 另外被复用的图像的像素格式 Config ( 如 RGB_565 ) 会覆盖设置的BitmapFactory.Options.inPreferredConfig 参数 ;*/if(bitmap.getWidth() == width &&bitmap.getHeight() == height && //被复用的图像宽高必须等于 解码后的图像宽高inSampleSize == 1){// 图像的 BitmapFactory.Options.inSampleSize 设置为 1//符合要求inBitmap = bitmap;iterator.remove();}}else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){/*在 Android 4.4(API 级别 19)及以上的版本中 ,只要被解码后的 Bitmap 对象的字节大小 , 小于等于 inBitmap 的字节大小 , 就可以复用成功 ;解码后的乳香可以是缩小后的 , 即 BitmapFactory.Options.inSampleSize 可以大于1 ;*/// 首先要计算图像的内存占用 , 先要计算出图像的宽高 , 如果图像需要缩放 , 计算缩放后的宽高if(inSampleSize > 1){width = width / inSampleSize ;height = height / inSampleSize;}// 计算内存占用 , 默认 ARGB_8888 格式int byteInMemory = width * height * 4;;if(bitmap.getConfig() == Bitmap.Config.ARGB_8888){// 此时每个像素占 4 字节byteInMemory = width * height * 4;}else if(bitmap.getConfig() == Bitmap.Config.RGB_565){// 此时每个像素占 2 字节byteInMemory = width * height * 2;}// 如果解码后的图片内存小于等于被复用的内存大小 , 可以复用if(byteInMemory <= bitmap.getAllocationByteCount()){//符合要求inBitmap = bitmap;iterator.remove();}}}else if( bitmap == null ){// 如果 bitmap 为空 , 直接从复用 Bitmap 集合中移除iterator.remove();}}return inBitmap;}/*下面的 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();}/*下面的 2 个方法是提供给用户用于操作 磁盘 的接口*//*** 将 Bitmap 放入 磁盘缓存 中* @param key* @param bitmap*/public void putBitmapToDisk(String key, Bitmap bitmap){DiskLruCache.Snapshot snapshot = null;OutputStream outputStream = null;try {snapshot = mDiskLruCache.get(key);// 如果缓存中有对应 key 键值的文件 , 不进行任何处理if(snapshot != null) {// 该用法与 SharedPreference 用法类似DiskLruCache.Editor editor = mDiskLruCache.edit(key);if(editor != null){// 这里的 0 表示获取该 key 对应的第 0 个文件// 每个 可以 可以对应多个文件 , 这个值是创建 DiskLruCache 时传入的 valueCount 参数outputStream = editor.newOutputStream(0);// 写出 Bitmap 对象到文件中bitmap.compress(Bitmap.CompressFormat.JPEG, 0, outputStream);// 该用法与 SharedPreference 用法类似editor.commit();}}} catch (IOException e) {e.printStackTrace();}finally {if(snapshot != null) {snapshot.close();}if(outputStream != null){try {outputStream.close();} catch (IOException e) {e.printStackTrace();}}}}/*** 从 磁盘缓存 中取出 Bitmap 对象* @param key       键值* @param inBitmap 复用 Bitmap 内存* @return*/public Bitmap getBitmapFromDisk(String key, Bitmap inBitmap){Bitmap bitmap = null;DiskLruCache.Snapshot snapshot = null;InputStream inputStream = null;try {snapshot = mDiskLruCache.get(key);// 如果缓存中有对应 key 键值的文件 , 不进行任何处理if(snapshot != null) {// 该用法与 SharedPreference 用法类似DiskLruCache.Editor editor = mDiskLruCache.edit(key);if(editor != null){// 这里的 0 表示获取该 key 对应的第 0 个文件// 每个 可以 可以对应多个文件 , 这个值是创建 DiskLruCache 时传入的 valueCount 参数inputStream = editor.newInputStream(0);BitmapFactory.Options options = new BitmapFactory.Options();options.inMutable = true;options.inBitmap = inBitmap;// 写出 Bitmap 对象到文件中bitmap = BitmapFactory.decodeStream(inputStream, null, options);if(bitmap != null){// 从磁盘读取后 , 先缓存到内存中mLruCache.put(key, bitmap);}// 该用法与 SharedPreference 用法类似editor.commit();}}} catch (IOException e) {e.printStackTrace();}finally {if(snapshot != null) {snapshot.close();}if(inputStream != null){try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}}return bitmap;}}

2、调用工具类代码示例


   /*** 图像磁盘内存缓存*/private void diskMemoryCache(){// 初始化 LruCache 内存缓存 , 与引用队列 , 一般在 onCreate 方法中初始化// 这里为了演示 , 放在方法的开头位置BitmapDiskLruCacheMemoryReuse.getInstance().init(this, Environment.getExternalStorageDirectory() + "/diskCache");// 1. 第一次尝试从 LruCache 内存中获取 Bitmap 数据Bitmap bitmap = BitmapDiskLruCacheMemoryReuse.getInstance().getBitmapFromLruCache(R.drawable.blog + "");/*如果从内存中获取 Bitmap 对象失败 , 再次从磁盘中尝试获取该 Bitmap*/if(bitmap == null){// 要复用内存的 Bitmap 对象 , 将新的 Bitmap 写入到该 Bitmap 内存中Bitmap inBitmap = null;// 尝试获取复用对象BitmapDiskLruCacheMemoryReuse.getInstance().getReuseBitmap(200, 200, 1);// 2. 第二次尝试从磁盘中获取图片bitmap = BitmapDiskLruCacheMemoryReuse.getInstance().getBitmapFromDisk(R.drawable.blog + "", inBitmap);// 磁盘中没有找到 , 再次尝试加载该图片if(bitmap == null) {// 3. 如果内存, 磁盘都没有获取到 Bitmap, 那么加载指定大小格式的图像bitmap = BitmapSizeReduce.getResizedBitmap(this, R.drawable.blog,200, 200, false, inBitmap);// 将新的 bitap 放入 LruCache 内存缓存中BitmapDiskLruCacheMemoryReuse.getInstance().putBitmapToLruCache(R.drawable.blog + "", bitmap);}}}

八、源码及资源下载


源码及资源下载地址 :

  • ① GitHub 工程地址 : BitmapMemory

  • ② BitmapDiskLruCacheMemoryReuse.java 工具类地址 : BitmapDiskLruCacheMemoryReuse.java

【Android 内存优化】Bitmap 硬盘缓存 ( Google 官方 Bitmap 示例 | DiskLruCache 开源库 | 代码示例 )相关推荐

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

    文章目录 一.Bitmap 内存缓存策略 二.LruCache 内存缓存 三.LruCache 常用操作 四.LruCache 工具类 五.源码及资源下载 官方参考 : Google 官方提供的 内存 ...

  2. 【Android 内存优化】Bitmap 内存缓存 ( Bitmap 内存复用 | 弱引用 | 引用队列 | 针对不同 Android 版本开发不同的 Bitmap 复用策略 | 工具类代码 )

    文章目录 一.Bitmap 复用池 二.弱引用 Bitmap 内存释放 三.从 Bitmap 复用池中获取对应可以被复用的 Bitmap 对象 1.Android 2.3.3(API 级别 10)及以 ...

  3. 桌面缓存服务器,primocache 把内存虚拟成硬盘缓存的硬盘优化软件

    primocache 是一款专业的硬盘优化软件,它的原理是把内存虚拟成硬盘缓存来实现硬盘优化,本次小编发布的是primocache,中包含两个版本分别是PrimoCache普通版和PrimoCache ...

  4. 【Android 内存优化】Bitmap 图像尺寸缩小 ( 考虑像素密度、针对从不同像素密度资源中解码对应的 Bitmap 对象 | inDensity | inTargetDensity )

    文章目录 一.像素密度对解码图片的影响 二.不考虑像素密度会导致图片缩小尺寸不准确 三.DisplayMetrics 源码阅读.研究手机资源获取规则 四.像素密度参数设置取值 ( inDensity ...

  5. 【Android 内存优化】Android 工程中使用 libjpeg-turbo 压缩图片 ( JNI 传递 Bitmap | 获取位图信息 | 获取图像数据 | 图像数据过滤 | 释放资源 )

    文章目录 一.Bitmap 图像数据处理 二.Java 层 Bitmap 对象转为 JNI 层 bitmap 对象 三.获取 bitmap 中的图像数据 四.过滤 bitmap 中的图像数据 ( 获取 ...

  6. Android 系统性能优化(39)---Android内存优化之三:打开MAT中的Bitmap原图

    Android内存优化之三:打开MAT中的Bitmap原图 在使用MAT查看应用程序内存使用情况的时候,我们经常会碰到Bitmap对象以及BitmapDrawable$BitmapState对象,而且 ...

  7. ANDROID内存优化(大汇总——中)

    转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 写在最前: 本文的思路主要借鉴了2014年AnDevCon开发者大会的一个演讲PPT,加上 ...

  8. 深入探索Android内存优化

    前言 成为一名优秀的Android开发,需要一份完备的知识体系,在这里,让我们一起成长为自己所想的那样~. 本篇是Android内存优化的进阶篇,难度会比较大,建议对内存优化不是非常熟悉的前仔细看看在 ...

  9. Android内存优化汇总

    写在最前: 本文的思路主要借鉴了2014年AnDevCon开发者大会的一个演讲PPT,加上把网上搜集的各种内存零散知识点进行汇总.挑选.简化后整理而成. 所以我将本文定义为一个工具类的文章,如果你在A ...

最新文章

  1. 2009 Competition Highlights by ICPC Live
  2. 【优秀奖】Java开发那点事征文
  3. Map .NET Concepts to the Lightning Platform——list,set,map
  4. windows下system函数的使用
  5. java怎么调用7zip进行压缩_JAVA使用7-zip解压缩带密码的Zip文件(非Proccess方法)...
  6. netty心跳过程中 发送消息失败_netty心跳机制和断线重连(四)
  7. 别在我的坟前哭 脏了我轮回的路
  8. File类的基本操作方法
  9. 计算机网络ospf配置命令,华为OSPF协议基本配置 -电脑资料
  10. DS4Windows(电脑PS4手柄控制器)v2.2.6 中文版
  11. 检测卡常见错误代码:12、12、2B、2C、2D、2E、2F、30、31、32、33、34、35、36、37、38、39、3A
  12. latex插入参考文献--BibTex格式
  13. deepin有线网卡无法连接网络
  14. mysql定义过程_mysql定义和调用存储过程
  15. swift野梦抄袭 taylor_断眉质疑Taylor Swift新歌抄袭《Next to Me》,双方粉丝掀起骂战...
  16. Java项目使用jib打包docker镜像的简单记录
  17. 屏幕亮度无法调节问题解决
  18. xmlserializer_更改XmlSerializer输出临时程序集的位置
  19. Sentiment Polarity Detection for Software Development
  20. Oracle删除数据效率低下案例

热门文章

  1. 简易而又灵活的Javascript拖拽框架(四)
  2. (3)数据库的建立和数据表的操作
  3. Java核心知识点 --- 线程中如何创建锁和使用锁 Lock , 设计一个缓存系统
  4. PHP实现简单的双色球机选号码
  5. POJ 3278 Catch That Cow(BFS)
  6. SQL Server 求结果
  7. iOS 9 学习系列:UIStack View
  8. POJ2699_The Maximum Number of Strong Kings
  9. The Simple Life
  10. 在Archlinuxarm上搭建Minecraft基岩服务器