
Flutter中的网络图片加载——以Glide为例
相对于Android而言。在Flutter中,加载网络图片,是很方便的一件事。通过Flutter提供的API就可以来实现。如下。
但使用后,很快就会发现一些问题,主要有以下几点。
- Flutter加载网络图片的API仅会将图片缓存在内存中,无法缓存本地。当内存中图片不存在时,又需要重新进行网络请求,这样一来就比较耗费资源。
- 如果在已有项目中添加Flutter模块,那么通过上面API就无法复用Android已有且成熟的网络图片处理模块。
- 如果是混合开发项目,那么针对同一张图片,无法做到Flutter模块与Android的内存间共享。
针对上述问题,目前已经存在一些解决方案。如通过cached_network_image来解决图片缓存本地问题;通过外接texture来实现同一张图片在Flutter模块与Android的内存间共享(可参考闲鱼Flutter图片框架架构演进(超详细)一文)。
而本文主要就是介绍通过Android已有的网络图片加载模块来实现Flutter中的网络图片加载。该方案可以复用Android中现有的图片处理模块及将图片缓存在本地,并且图片在本地仅保存一次。但要注意的是,该方案无法实现同一张图片在Flutter模块与Android的内存间共享。
由于在Android开发中,通过Glide来加载网络图片比较普遍。所以本文也就以Glide为例。
1、网络图片的加载
整体实现方案很简单,就是通过Glide来下载图片,待下载成功后通过Platform Channel将图片路径传递给Flutter,最后再通过图片路径来加载。这样图片在本地仅会保存一次。
先来看Flutter端代码的实现。
再来看Android端代码的实现。
经过上面代码,就实现了Flutter通过Glide来加载网络图片。
上面代码中省略了Platform Channel使用的代码,但如果对于Platform Channel的使用不熟悉,可以参考Flutter与Android间通信一文。
2、图片内存占用优化
再来看上面代码中使用的cacheWidth与cacheHeight字段,它们在文档中的说明如下。
If [cacheWidth] or [cacheHeight] are provided, it indicates to the engine that the image must be decoded at the specified size. The image will be rendered to the constraints of the layout or [width] and [height] regardless of these parameters. These parameters are primarily intended to reduce the memory usage of [ImageCache].
简单翻译下,cacheWidth与cacheHeight是图片在内存缓存中的宽与高,设置该值可以减小图片在内存中的占用。因此我们可以根据widget的宽高与图片的实际宽高来进行缩放,从而减小图片在内存中的占用。
因此,我们就可以根据cacheWidth与cacheHeight来优化上面代码。
经过上面代码的优化,Flutter通过Glide来加载网络图片基本上就没啥大问题了。
3、列表加载图片优化
再来看一个非常常见的应用场景,列表中加载网络图片。在Android中,Glide针对列表有专门的优化,在快速滑动时,不会进行图片的加载。那么这在Flutter中该怎么实现尼?
其实在Flutter中已经帮我们做了关于快速滑动时的处理,下面来看Image组件的实现代码。
上面代码中的ScrollAwareImageProvider就是Image在快速滑时的处理,再来看该类的实现。
上面代码很简单,重点就是判断当前是否在快速滑动。如果在快速滑动就等待下一帧,否则就将图片展示在界面上。
由于Flutter在快速滑动时做了处理,所以基本上不需要再次进行优化,就可以把上面的图片加载方案使用在列表中。但在使用时,还是发现了存在的一个小问题,就是当快速滑动时,每帧的绘制时间会超过16ms。经过仔细排查,主要是由于快速滑动时,每个item的淡入淡出动画还需要执行,从而导致了每帧绘制时间的延长。
所以需要列表快速滑动时取消item的淡入淡出动画。具体实现代码如下。
4、总结
前面两小结中优化过后的代码就是本文方案的最终实现,做到了混合项目中复用已有的图片加载模块及图片仅在本地保存一次。但还是无法做到图片在Flutter与Native间的内存共享,也无法做到图片在多Engine的内存间共享,而关于闲鱼通过外接texture方案来实现图片的内存间共享有一定实现复杂度,所以这种实现方案待后面再来分享。
此外,Flutter的Image组件可以很方便的加载gif与webp,所以上述方案的实现也是能够加载gif与webp。
作者:大逗大人
来源:掘金
