腾讯出品Pag动画框架在Android端的使用-网络Pag加载

在我们可以通过assets的方式加在pag文件之后,我们会考虑下一个问题,可不可以用Pag框架加载网络文件?

为什么会有这样的问题出现,或者说网络方式加载可以解决什么问题?

  1. APK 体积增加问题

当一个项目规模比较大的时候,会做很多优化工作,其中「APK瘦身」便是一项优化点。通过网络的方式加载可以减少内置文件,从而降低APK大小。

  1. 热更新问题

我们有时候是有这样的需求的,线上更改动画效果,通过网络方式便可以做到。

  1. 新的功能或者组件上线,需要更新客户端问题。

在某些功能中,比如我们现有的图片列表类的,只要线上的api返回新的图片地址即可;那么对于pag,我们也想要有这样的效果。

and more……

有了以上的问题,我们决定做「网络加载Pag」功能!

一、做网络加载Pag需要考虑什么?(其实是所有的网络加载需要考虑的事情)

1、下载器

网络加载的第一步肯定是下载,那么选择一个合适的下载器是十分重要的,这个下载器最好支持什么功能?

  1. 多线程下载(同时需要服务端支持,下载时可指定range)

  2. 断点续传

  3. 通用性(其他位置也可以)

  4. 任务队列(任务优先级等)

  5. 暂停、继续

  6. 下载失败文件处理

2、缓存策略

我们熟知的缓存策略可能就是Glide中的图片三级缓存策略了。其实不止图片,所有的缓存策略基本上就是这三级:

1、 内存缓存

2、磁盘缓存

3、网络(严格意义上来讲,这不算是个缓存)

既然是缓存,就需要考虑缓存的清理策略。我们熟知有的LruCache、DiskLruCache。根据项目的实际情况选择即可。

3、文件校验

为什么需要文件校验,其实有很多原因。但大多数无外乎以下几种:

  1. 文件完整性。我们加载损坏的文件,肯定是展示不出内容的。除非只损换了padding,也就是字节填充部分的内容

  2. 文件安全性。我们的文件如果中途被人篡改,我们可以通过此种方式来校验安全性。当然安全性校验一般会通过MD5、SHA256等哈希算法进行校验,会增加读取文件耗时。

  3. 文件校验失败后的重新下载。一般文件校验失败了,也就证明当前缓存是有问题的,或者中间被人篡改了。这时根据当前文件是缓存还是直接下载的文件,去做对应的处理。如果是缓存文件,会直接删除重新下载,如果非缓存文件,可能提示出错等。

二、Pag文件网络加载具体怎么做?

先说明:如果你使用的是4.3.3版本(包含)后的pag,它的sdk已经内置了网络加载功能,可以直接指定一个url地址的。

当然如果你的项目中需要统一处理缓存,统一下载,或者已经有了成熟的下载器框架。就需要自己搭建一个Pag网络加载方案了。

1、使用Glide加载?

我第一步的考虑是能否通过扩展Glide来增加对Pag文件的支持,为什么会这么考虑,因为Glide已经支持了三级缓存功能,我没必要再实现一次。Glide也有下载功能,我没有必要再实现一次。

我也去网上查了,确实有这样的方案的。但是后来我没采用。原因有下:

  1. 新的Pag文件缓存会占用Glide中配置的缓存空间大小,会影响原本图片缓存。

  2. 项目内部已经有了针对项目的缓存策略,如果使用Glide会打乱原有非图片文件的缓存策略,不方便统一管理。

  3. 现有的下载器,支持多线程下载,可以提升大文件下载速度。

2、新创建加载Pag框架。

后面还是决定自己Pag。基本的流程是这样。

  1. 根据Url的MD5判断本地是否有缓存。

  2. 有缓存

    1. 校验缓存是否完整(没有做安全性校验,因为这个动画文件,感觉没必要)。自己根据Pag文件的格式写了一个校验工具。(后来发现没卵用,给删除了)

    2. 若完整,直接加载

    3. 若加载失败,重新下载。

  3. 无缓存

    1. 下载器下载

    2. 下载成功后,PagFile.load()。

打完收工,基本上我测试了一下没啥问题。

源码就不上了,只要是思路比较重要。

遇到的问题

我不是自己写了个校验工具,我为啥写了个校验工具呢?因为我调用PagFile.load方法发现,返回的是非空的类型(它的代码中没有标记@NonNull),于是我认为即使它加载错了,也会返回一个非空对象,那我何不自己先校验一下。于是翻Pag的源码,根据它内部的校验规则,我先提前一步校验了。

结果问题出现了,有一个损坏了的文件,通过了我的校验工具检验,但是没加载出来,并在Log中看到了 Invild File。

后来我发现,因为PagFile的代码是java代码,而且没有被@Nonnull标记,而我们项目中用的是Kotlin,这样会导致一个什么问题,Kotlin认为该文件是非空的。

于是查阅pag源码,发现在C层的代码里,当加载文件失败时(这个过程会走文件校验),会直接返回一个nullptr,也就是空指针。于是我将自己的校验工具去掉了,直接判断Load的结果,如果是空则证明加载失败了,而加载失败的最大可能就是,文件错了,此时走重新下载,或者其他处理即可。

伪代码:


val result = PAGFile.Load(file.path) 
if (result == null) { downloadIt() } 
else { pagView.componsition = result }



猜你喜欢

转载自blog.csdn.net/yztbydh/article/details/132255220