《android开发艺术探索》读书笔记(十二)--Bitmap的加载和Cache
接上篇《android开发艺术探索》读书笔记(十一)--Android的线程和线程池
No1:
目前比较常用的缓存策略是LruCache和DiskLruCache,LruCache常被用作内存缓存,DiskLruCache常被用作存储设备缓存。
Lru是Least Recently Used的缩写,即最近最少使用算法,当缓存快满时,会淘汰近期最少使用的缓存目标。
No2:
LruCache:
LruCache是一个泛型类,它内部采用一个LinkedHashMap以强引用的方式存储外界的缓存对象,其提供了get和put方法来完成缓存的获取和添加操作,当缓存满时,LruCache会移除较早使用的缓存对象,然后再添加新的缓存对象。
LruCache是线程安全的
public class LruCache<K,V>{ private final LinkedHashMap<K,V> map; ... }
初始化过程
int maxMemory = (int)(Runtime.getRuntime().maxMemory()/1024); int cacheSize = maxMemory/8; mMemoryCache = new LruCache<String,Bitmap>(cacheSize){ @Override protected int sizeOf(String key,Bitmap bitmap){ return bitmap.getRowBytes()*bitmap.getHeight()/1024; } };
获取一个缓存对象
mMemoryCache.get(key)
添加一个缓存对象
mMemoryCache.put(key,bitmap)
No3:
DiskLruCache创建
private static final long DISK_CACHE_SIZE = 1024*1024*50;//50MB File diskCacheDir = getDiskCacheDir(mContext,"bitmap"); if(!diskCacheDir.exists()){ diskCacheDir.mkdirs(); } //磁盘缓存在文件系统中的存储路径,应用的版本号,单个节点对应的数据个数,缓存的总大小 mDiskLruCache = DiskLruCache.open(diskCacheDir,1,1DISK_CACHE_SIZE);
建议:如果应用卸载后就希望删除缓存文件,俺么就选择SD卡上的缓存目录,如果希望保留缓存数据那就应该选择SD卡上的其他特定目录
No4:
DiskLruCache的缓存添加:
操作是通过Editor完成的,Editor表示一个缓存对象的编辑对象。
例如:首先需要获取图片url所对应的key,然后根据key就可以通过edit()来获取Editor对象
//一般采用url的md5值作为key String key hashKeyFormUrl(url); DiskLruCache.Editor editor = mDiskLruCache.edit(key); if(editor != null){ //DISK_CACHE_INDEX常量设为0 OutputStream outputStream = editor.newOutputStream(DISK_CACHE_INDEX); }
必须通过Editor.commit()来提交写入操作,如果过程发生异常,可以通过Editor.abort()来回退整个操作。
No5:
DiskLruCache缓存查找
Bitmap bitmap = null; String key = hashKeyFormUrl(url); DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key); if(snapShot!=null){ FileInputStream fileInputStream = (FileInputStream)snapShot.getInputStream(DISK_CACHE_INDEX); FileDescriptor fileDescriptor = fileInputStream.getFD(); bitmap = mImageResizer.decodeSampledBitmapFromFileDescriptor(fileDescriptor,reqWidth,reqHeight); if(bitmap!=null){ addBitmapToMemoryCache(key,bitmap); } }
No6:
No7:
优化列表的卡顿现象
1)不要在Adapter的getView中执行耗时操作,必须异步处理
2)控制异步任务的执行频率:ListView和GridView在滑动的时候停止加载图片
public void onScrollStateChanged(AbsListView view,int scrollState){ if(scrollState == OnScrollListener.SCROLL_STATE_IDLE){ mIsGridViewIdle = true; mImageAdapter.notifyDataSetChanged(); }else{ mIsGridViewIdle = false; } }
在getView中,仅当列表静止时才能加载图片
if(mIsGridViewIdle && mCanGetBitmapFromNetWork){ imageView.setTag(uri); mImageLoader.bindBitmap(uri,imageView,mImageWidth,mImageWidth); }
3)开启硬件加速
android:hardwareAccelerated="true"
为Activity开启硬件加速
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现