每次启动app fresco缓存路径框架的文件缓存都被清理掉怎么回事

android开发总结(59)
本文由hss01248投稿。
hss01248的博客地址:
http://blog.csdn.net/hss01248
本文是作者在使用Fresco过程中一些经验分享,包含了大量的经验,针对一些场景都给出处理的方案,感谢作者分享。
[Fresco](/facebook/fresco)&是Facebook开源的安卓上的图片加载框架,也可以说是至今为止安卓上最强大的图片加载框架。
相对于其他几个图片加载框架,Fresco主要的优点在于更好的内存管理和更强大的功能,更便捷的使用,缺点则是体积比较大,引入后会导致应用apk增加1.5M到2M的大小,但是相对于其便捷性来讲,我觉得这都不是事儿.
优点一:内存管理
对于5.0以下系统,fresco使用”ashmem”(匿名共享内存)区域存储Bitmap缓存,这样Bitmap对象的创建、释放将不会触发GC,不会占用javaheap.这个特点是其他图片加载框架所没有做到的.
5.0以上系统,由于安卓系统本身内存管理的优化,所以对于5.0以上的系统Fresco将Bitmap缓存直接放到了javaheap内存中.并且,fresco实现了真正的三级缓存:两级的内存缓存+一个磁盘缓存.两个内存缓存为:bitmap缓存 和未解码的图片缓存,这样既可以加快图片的加载速度,又能节省内存的占用.这个两级的内存缓存也是其他图片加载框架所没有做到的.
另外提一点,在app切换到后台时,fresco会自动清理两级的内存缓存,无需手动.
通过以上几点,使用fresco加载图片时内存占用要比其他图片加载框架小一大半,基本很少发生oom的事情.
几个图片加载框架的内存占用测试结果对比请戳这里:
优点二:更便捷的使用:
另外再说一句,fresco还支持webp,所以,splash和引导界面的大图我一般都是用智图(http://zhitu.isux.us/)压成webp放在drawable中,用fresco加载就行了.
首先,终极的解决方法肯定是,客户端在图片请求中带上需要的宽和高,服务器将图片缩略到该规格后返回该小图.这个做得比较好的是七牛.
注意:不管服务器能不能返回缩略图,所存储的原图都不应该太大,有时图片太大,甚至都无法下载下来(报504之类的错误).
fresco中提供了三个功能来[生成缩略图](http://www.fresco-cn.org/docs/resizing-rotating.htm):
综上,要缩小内存占用,以及减少cpu计算量,减少卡顿,应该是Downsampling结合Resizing来使用.其中Downsampling是在Fresco初始化时开启,而Resizing则是通过构建ImageRequest时通过制定宽高来实现,所以可以定制每一张或每一类图片的宽高. 示例代码如下:
利用SimpleDraweeView加载图片的一般姿势:
注意,我这里没有去设置DraweeHierarchy,因为依照fresco的设计思维,DraweeHierarchy属于view层次的东西,应该在xml中配置.当然如果非要设置,请看这里(http://fresco-cn.org/docs/using-drawees-code.html).
如何避免显示图片时把人的脸部截掉。
这个就要用到Scaling了.图片的缩放拉伸以及裁剪模式.具体看文档(http://fresco-cn.org/docs/scaling.html#_)
可用的缩放类型:
& 居中,无缩放。
centerCrop &
& 保持宽高比缩小或放大,使得两边都大于或等于显示边界,且宽或高契合显示边界。居中显示。
focusCrop&
& 同centerCrop, 但居中点不是中点,而是指定的某个点。
centerInside &
& 缩放图片使两边都在显示边界内,居中显示。和 fitCenter 不同,不会对图片进行放大。如果图尺寸大于显示边界,则保持长宽比缩小图片。
fitCenter&
& 保持宽高比,缩小或者放大,使得图片完全显示在显示边界内,且宽或高契合显示边界。居中显示。
fitStart &
& 同上。但不居中,和显示边界左上对齐。
& 同fitCenter, 但不居中,和显示边界右下对齐。
& 不保存宽高比,填充满显示边界。
& 如要使用tile mode显示, 需要设置为none
这些缩放类型和Android&ImageView&支持的缩放类型几乎一样.
图片默认是centerCrop,那么在用一个横向的SimpleDraweeView来显示一张竖着拍的人像时,就很可能把人的头部给截掉了,但对于在listview中展示的SimpleDraweeView来说,我们又无法用focusCrop直接指定其居中点在图片上半部分某个地方,因为其他图片可能是横着拍的或很正方形的自拍,这个时候怎么办?
就需要根据人脸的检测来设置focusCrop的那个点了,而android从sdk 1.0开始就已经提供了一个人脸识别的类FaceDetector(/mainroadlee/p/android_sdk_face_detection.html),原理是通过找眼睛来识别人脸,可以拿到眼睛的中心点坐标,那么根据该坐标,结合图片本身的宽高,计算出针对每张图片的focusCrop 需要设置的点,就能够解决这个问题了.
//TODO 这个还没有去写方法,但有一个开源项目facecropper(/lafosca/AndroidFaceCropper/blob/master/FaceCropper-library/src/main/java/cat/lafosca/facecropper/FaceCropper.java)可以参考,他们的做法是将一个大的bitmap截图成小的bitmap。
对于内存的缓存,fresco根据图片Uri,以及图片的resising参数和processor参数综合生成缓存key来缓存bitmap,而磁盘文件缓存则是只根据Uri生成key,那么,如果要获取文件缓存,只需要知道uri和通过key取file的api就行了,原先的调用链较长,故封装成单个方法:
需要注意的是文件名后缀不是普通的图片后缀(.jpg之类的),而是.cnt,但都是二进制文件,可以将文件直接拷贝到指定路径重命名成正常图片后缀即可.当然如果只是读取到内存做其他用途,可以直接读取,无需拷贝更改后缀,不影响使用.
以下是读取缓存文件的方法.而拷贝到其他文件目录的方法也已封装好于FrescoUtils中.
由于某种原因无法使用SimpleDraweeView来显示图片(比如说弹幕上显示头像),而需要直接操作bitmap,那么要怎么拿到url返回的bitmap?
自己构建图片请求,然后类似上面的文件下载,还是采用DataSubscriber来监听回调,只不过返回的不是void,而是CloseableImage的bitmap,
注意,此bitmap对象的缓存由Fresco管理,所以不要去调用bitmap.recycle()之类的方法.
对此bitmap的一些处理,如果处理后的bitmap对象还是指向该bitmap引用,会影响到其他同样url,width height,并且同样Postprocessor的图片组件的显示,比如,将该bitmap高斯模糊了,就会影响到其他的这四个参数相同的SimpleDraweeView的显示.
那么,如果要不影响,怎么办?很简单,让四个参数任一一个不同就行.
话不多说,直接看代码.
gif图片无法显示成圆形,怎么办?(当然有的情况下,jpg也无法显示圆形) –加一层和图片的parentview 背景色一样的圆形遮罩即可:
很多app都有清除磁盘缓存的功能,那么fresco怎么清除缓存呢?
高斯模糊是app里设置一些背景效果 常用到的手段.
在fresco中,可以通过postprocessor来实现,也可以自己拿到bitmap后将bitmap模糊化后设置到ImageView或SimpleDraweeView(这个不建议,会消除掉SimpleDraweeView的层级结构,变成单纯的ImageView)上.
推荐前一种: 用到别人封装好的BlurPostprocessor(/wasabeef/fresco-processors/blob/master/processors/src/main/java/jp/wasabeef/fresco/processors/BlurPostprocessor.java)&:
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:96521次
积分:1384
积分:1384
排名:千里之外
原创:32篇
转载:60篇
评论:12条
(4)(4)(1)(2)(2)(2)(4)(4)(1)(1)(1)(3)(1)(1)(1)(1)(2)(2)(7)(12)(18)(1)(2)(2)(12)(1)4602人阅读
Android(62)
这篇是随手写的,有博友在楼下提问相关问题。
这里先把我知道的方案放这里,以后有空详细写。
另外,请注意:虽然我找到了如何清理缓存的方法,但是目前还未实际测试过。请自行测试哦。
public class ImagePipelineConfigUtils {
private static final int MAX_HEAP_SIZE = (int) Runtime.getRuntime().maxMemory();
private static final int MAX_MEMORY_CACHE_SIZE = MAX_HEAP_SIZE / 4;
private static final int MAX_SMALL_DISK_VERYLOW_CACHE_SIZE = 20 * ByteConstants.MB;
private static final int MAX_SMALL_DISK_LOW_CACHE_SIZE = 60 * ByteConstants.MB;
private static final int MAX_DISK_CACHE_VERYLOW_SIZE = 20 * ByteConstants.MB;
private static final int MAX_DISK_CACHE_LOW_SIZE = 60 * ByteConstants.MB;
private static final int MAX_DISK_CACHE_SIZE = 100 * ByteConstants.MB;
private static final String IMAGE_PIPELINE_SMALL_CACHE_DIR = "ImagePipelineCacheSmall";
private static final String IMAGE_PIPELINE_CACHE_DIR = "ImagePipelineCacheDefault";
public static ImagePipelineConfig getDefaultImagePipelineConfig(Context context) {
final MemoryCacheParams bitmapCacheParams = new MemoryCacheParams(
MAX_MEMORY_CACHE_SIZE,
Integer.MAX_VALUE,
MAX_MEMORY_CACHE_SIZE,
Integer.MAX_VALUE,
Integer.MAX_VALUE);
Supplier&MemoryCacheParams& mSupplierMemoryCacheParams = new Supplier&MemoryCacheParams&() {
public MemoryCacheParams get() {
return bitmapCacheP
DiskCacheConfig diskSmallCacheConfig = DiskCacheConfig.newBuilder().setBaseDirectoryPath(context.getApplicationContext().getCacheDir())
.setBaseDirectoryName(IMAGE_PIPELINE_SMALL_CACHE_DIR)
.setMaxCacheSize(MAX_DISK_CACHE_SIZE)
.setMaxCacheSizeOnLowDiskSpace(MAX_SMALL_DISK_LOW_CACHE_SIZE)
.setMaxCacheSizeOnVeryLowDiskSpace(MAX_SMALL_DISK_VERYLOW_CACHE_SIZE)
.setDiskTrimmableRegistry(NoOpDiskTrimmableRegistry.getInstance())
DiskCacheConfig diskCacheConfig = DiskCacheConfig.newBuilder().setBaseDirectoryPath(Environment.getExternalStorageDirectory().getAbsoluteFile())
.setBaseDirectoryName(IMAGE_PIPELINE_CACHE_DIR)
.setMaxCacheSize(MAX_DISK_CACHE_SIZE)
.setMaxCacheSizeOnLowDiskSpace(MAX_DISK_CACHE_LOW_SIZE)
.setMaxCacheSizeOnVeryLowDiskSpace(MAX_DISK_CACHE_VERYLOW_SIZE)
.setDiskTrimmableRegistry(NoOpDiskTrimmableRegistry.getInstance())
ImagePipelineConfig.Builder configBuilder = ImagePipelineConfig.newBuilder(context)
.setBitmapsConfig(Bitmap.Config.RGB_565)
.setBitmapMemoryCacheParamsSupplier(mSupplierMemoryCacheParams)
.setSmallImageDiskCacheConfig(diskSmallCacheConfig)
.setMainDiskCacheConfig(diskCacheConfig)
.setMemoryTrimmableRegistry(NoOpMemoryTrimmableRegistry.getInstance())
.setResizeAndRotateEnabledForNetwork(true);
NoOpMemoryTrimmableRegistry.getInstance().registerMemoryTrimmable(new MemoryTrimmable() {
public void trim(MemoryTrimType trimType) {
final double suggestedTrimRatio = trimType.getSuggestedTrimRatio();
Loger.d(String.format("onCreate suggestedTrimRatio : %d", suggestedTrimRatio));
if (MemoryTrimType.OnCloseToDalvikHeapLimit.getSuggestedTrimRatio() == suggestedTrimRatio
|| MemoryTrimType.OnSystemLowMemoryWhileAppInBackground.getSuggestedTrimRatio() == suggestedTrimRatio
|| MemoryTrimType.OnSystemLowMemoryWhileAppInForeground.getSuggestedTrimRatio() == suggestedTrimRatio
ImagePipelineFactory.getInstance().getImagePipeline().clearMemoryCaches();
return configBuilder.build();
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:162493次
积分:3090
积分:3090
排名:第8769名
原创:131篇
评论:126条
文章:21篇
阅读:4499
阅读:13401
(2)(2)(4)(6)(30)(13)(6)(3)(1)(1)(3)(4)(12)(4)(2)(1)(2)(4)(27)(3)(2)(2)(1)(1)(1)(1)114网址导航关于Fresco的缓存清理的那些事_android开发_ThinkSAAS
关于Fresco的缓存清理的那些事
关于Fresco的缓存清理的那些事
我相信很多人对Fresco这个优秀的第三方网络图片处理框架不陌生,无论从使用还是配置而言都是很人性化的简单,今天要讲述的是我遇到的关于缓存清理的事情。
Fresco自身的缓存清理时机
当我们手动退出整个app的时候,发现之前加载过的图片不会出现重新加载的情况,说明这种情况下,缓存依旧还在。但是当我们通过手机的后台关闭app的时候,就会出现重新加载,缓存也没了。这个是我们人为测出来的,你们也可以试试,这是Fresco自身的一个清理机制。
Fresco的缓存哪里统计
用过这个框架的人很多,但是真的去计算他的缓存了多少的人,貌似并不多,我也是百度了无数,然而并没有找到答案,我一度以为也许是他封装处理的太深了,后来去看源码,准备做最后的策略,找到他的缓存文件夹的目录,然后计算文件夹的大小,这也是很多第三方网络图片加载计算缓存的一个套路方式,这个方法可行,但是麻烦了点,最终我在google上一个老外的帖子里面,看到了方法,大家可以看看
private void showCacheSize(){
ivClean.setVisibility(View.INVISIBLE);
tvCacheSize.setVisibility(View.VISIBLE);
long cacheSize = Fresco.getImagePipelineFactory().getMainDiskStorageCache().getSize();
if(cacheSize&=0){
tvCacheSize.setText("0.00B");
float cacheSizeTemp1 = CommUtil.changToTwoDecimal(Math.round(cacheSize / 1024));
float cacheSizeTemp2 = CommUtil.changToTwoDecimal(Math.round((cacheSize/));
if(cacheSizeTemp1&1){
tvCacheSize.setText(cacheSize+"B");
}else if(((cacheSizeTemp1&=1)&&(cacheSizeTemp2&1))){
tvCacheSize.setText(cacheSizeTemp1+"KB");
}else if(cacheSizeTemp2&=1){
tvCacheSize.setText(cacheSizeTemp2+"MB");
这个显示方法是我自己写,大家只要看到核心的那句
long cacheSize =Fresco.getImagePipelineFactory().getMainDiskStorageCache().getSize();
这是最简单的方式了没有之一,这是显示的部分,让我们再看看如何清理
Fresco的缓存如何清理
一般来说我们都不太需要手动去清理,因为Fresco本身就带有自我清理的机制,详情看上面的清理时机,但是当我们的app需要一个清理缓存的功能的需求的时候,一言不合就去找方法,很欣慰我们还是找到了
case id.tvCleanCache:
ImagePipeline imagePipeline = Fresco.getImagePipeline();
imagePipeline.clearCaches();
ivClean.setVisibility(View.VISIBLE);
tvCacheSize.setVisibility(View.INVISIBLE);
new Handler().postDelayed(new Runnable() {
public void run() {
showCacheSize();
因为我们需要一个表示在清理的过程动画,清理缓存的关键代码就是
ImagePipeline imagePipeline = Fresco.getImagePipeline();
imagePipeline.clearCaches();
这样就清理了,你会发现之前的加载的图片又会重新加载了,成功了!
实践才是最好的学习方式,本篇文章不难,只是找寻答案的过程很重要,是一个程序员自我完善的一个学习过程,希望能help到有需要的朋友,
PHP开发框架
开发工具/编程工具
服务器环境
ThinkSAAS商业授权:
ThinkSAAS为用户提供有偿个性定制开发服务
ThinkSAAS将为商业授权用户提供二次开发指导和技术支持
让ThinkSAAS更好,把建议拿来。
开发客服微信

我要回帖

更多关于 fresco 缓存 的文章

 

随机推荐