文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Android Fresco图片加载优化的方案

2024-04-02 19:55

关注

优化背景

一般情况下,Fresco图片加载需使用SimpleDraweeView,这个控件并不能自动根据自身的尺寸按需加载图片,即一个 N×N 的UI控件,背后加载的实际图片可能是 2N×2N。这就导致了实际应用运行过程中的内存使用效率不高,需要针对其进行内存优化。

在一些入门级硬件设备上,表现得尤为明显,随着程序的运行时间的增长,OOM的风险也不断加大。

Fresco版本:1.13.0

数据记录

声明控件大小为 480×270


<com.facebook.drawee.view.SimpleDraweeView
  android:id="@+id/simple_drawee_view"
  android:layout_width="480dp"
  android:layout_height="270dp"
  android:layout_alignParentBottom="true"
  android:layout_centerHorizontal="true"
  app:layout_constraintBottom_toBottomOf="parent"
  app:layout_constraintLeft_toLeftOf="parent"
  app:layout_constraintRight_toRightOf="parent"
  app:layout_constraintTop_toTopOf="parent" />

加载图片代码,调用Fresco的setImageURI


val mImageUrl = "https://static.runoob.com/images/demo/demo4.jpg"
val simple_drawee_view = findViewById<SimpleDraweeView>(R.id.simple_drawee_view)
simple_drawee_view.setImageURI(mImageUrl)

运行后dump内存如下,可以发现内存中的图片尺寸为1920×1080,即此时SimpleDraweeView会按照网络上的原图尺寸进行加载,内存占用大小为 8294475Bytes = 7.91Mb。一张图片占用近8Mb,在图片显示十分丰富的页面场景中,图片总内存占用大小将特别美丽,万一这个页面又内存泄漏了,那就更美丽了。

如果只加载 480×270 大小的图片,内存占用为 518475Bytes = 0.49Mb。相较于原来 1920×1080 尺寸,内存减小了 94%!

优化方案

Fresco提供了resize api,使得调用者在图片解码前可以修改内存中图片的大小,api大致如下


ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
 .setResizeOptions(new ResizeOptions(width, height))
 .build();
PipelineDraweeController controller = Fresco.newDraweeControllerBuilder()
 .setOldController(mDraweeView.getController())
 .setImageRequest(request)
 .build();
mSimpleDraweeView.setController(controller);

注意这个方案在低版本中默认只支持jpg图片,如需支持其它图片格式,需在设置image pipeline时添加isDownSample配置。同时对于产生的图片的尺寸,只能粗略地控制,图片不能修改为确定的尺寸。


.setDownsampleEnabled(true)

这个方案有个显著的缺点,那就是页面适配性极差,需要配合View层的生命周期在确保能够动态获取到控件宽高的时机进行调用,对于一个成熟的项目工程,代码改动量过大,优化成本过高。 这里采用编写SimpleDraweeView的子类进行优化,利用向上转型,尽可能的减小View层代码的改动,只需要修改xml布局文件中的控件声明即可。 方案架构图如下:

其中DesiredSimpleDraweeView为SimpleDraweeView的子类,在onWindowFocusChanged方法回调中可以明确获知控件的具体宽高,之后再进行图片加载操作。


public class DesiredSimpleDraweeView extends SimpleDraweeView {

 Uri mUri;
 Object mCallerContext;

 public DesiredSimpleDraweeView(Context context) {
  super(context);
 }

 @Override
 public void setImageURI(Uri uri, Object callerContext) {
  mUri = uri;
  mCallerContext = callerContext;
 }

 private void setImageURI(int width, int height) {
  try {
   ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(mUri)
     .setResizeOptions(new ResizeOptions(width, height))
     .build();
   DraweeController controller =
     getControllerBuilder()
       .setOldController(getController())
       .setImageRequest(imageRequest)
       .build();
   setController(controller);
  } catch (Exception ex) {
   ex.printStackTrace();
  }
 }

 @Override
 public void onWindowFocusChanged(boolean hasWindowFocus) {
  super.onWindowFocusChanged(hasWindowFocus);
  if (hasWindowFocus) {
   setImageURI(getWidth(), getHeight());
  }
 }
}

复写setImageURI(Uri,Object)方法,暂存uri和callerContext,在onWindowFoucusChanged回调之后再根据控件宽高进行图片的加载。 这样,利用向上转型,View层的代码无需改动,xml文件中替换控件声明后即可显著提高内存利用率。

注意事项

性能优化是条永无止境的道路,没有最牛逼的方案,只有最合适的方案。如果对于图片加载尺寸想要精确控制,按需加载,Glide或许是更好的选择。

以上就是Android Fresco图片加载优化的方案的详细内容,更多关于Android Fresco图片加载优化的资料请关注编程网其它相关文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯