关于安卓SVGA浅尝(二)加载数据

关于安卓SVGA浅尝(二)加载数据

请添加图片描述

相关链接

SVGA官网
SVGA-github说明文档

背景

项目开发,都会和动画打交道,动画的方案选取,就有很多选择。如Json动画,svga动画,gif等等。各有各的优势。目前项目中用到了svga的动画,因此,就有了这一系列的文章。

实现

对于svga的加载方法,有以下几种:
(1)decodeFromURL()
(2)decodeFromAssets()

对于(1)方法,就是从网络url加载一个url并在本地显示的意思。方法(2),就是读取本地assets文件进行显示。
方法(1)的实现逻辑,具体如下:
1、对传入的数据进行一个数据转换,得出一个数据缓存的key值。
2、若key值对应的缓存存在,则直接加载数据(区分是默认缓存路径还是其他缓存路径)
3、否则进行网络请求,通过HttpURLConnection请求写入得出一个ByteArrayInputStream对象后回调外部,执行
SVGAVideoEntity对象的封装后,回调出外部并交由外部执行。(这里得出ByteArrayInputStream后的逻辑,和
decodeFromAssets()方法读取文件后的逻辑,是一致的,都是调用decodeFromInputStream()这个防范进行处理)


而最后通过“流”到构建出“SVAVideoEntity”过程中,构造方法有一段这样的代码:

    constructor(entity: MovieEntity, cacheDir: File, frameWidth: Int, frameHeight: Int) {
        this.mFrameWidth = frameWidth
        this.mFrameHeight = frameHeight
        this.mCacheDir = cacheDir
        this.movieItem = entity
        entity.params?.let(this::setupByMovie)
        try {
            parserImages(entity)
        } catch (e: Exception) {
            e.printStackTrace()
        } catch (e: OutOfMemoryError) {
            e.printStackTrace()
        }
        resetSprites(entity)
    }

核心代码,就是parserImages(entity)这个方法,里面的实现源码如下:

    private fun parserImages(obj: MovieEntity) {
        obj.images?.entries?.forEach { entry ->
            val byteArray = entry.value.toByteArray()
            if (byteArray.count() < 4) {
                return@forEach
            }
            val fileTag = byteArray.slice(IntRange(0, 3))
            if (fileTag[0].toInt() == 73 && fileTag[1].toInt() == 68 && fileTag[2].toInt() == 51) {
                return@forEach
            }
            val filePath = generateBitmapFilePath(entry.value.utf8(), entry.key)
            createBitmap(byteArray, filePath)?.let { bitmap ->
                imageMap[entry.key] = bitmap
            }
        }
    }

可以看出,这里对传入对象的images集合类进行了遍历,最后通过createBitmap方法,创建了一个对象,
并且赋值给了SVAVideoEntity这个对象中的imageMap集合。
而对于parserImages方法中的入参“MovieEntity”,大部分都是通过方法“MovieEntity.ADAPTER.decode”进行对象构建。
这个方法是依赖于com.opensource.svgaplayer.proto这个包目录下的的方法在MovieEntity如下:

    @Override
    public MovieEntity decode(ProtoReader reader) throws IOException {
      Builder builder = new Builder();
      long token = reader.beginMessage();
      for (int tag; (tag = reader.nextTag()) != -1;) {
        switch (tag) {
          case 1: builder.version(ProtoAdapter.STRING.decode(reader)); break;
          case 2: builder.params(MovieParams.ADAPTER.decode(reader)); break;
          case 3: builder.images.putAll(images.decode(reader)); break;
          case 4: builder.sprites.add(SpriteEntity.ADAPTER.decode(reader)); break;
          case 5: builder.audios.add(AudioEntity.ADAPTER.decode(reader)); break;
          default: {
            FieldEncoding fieldEncoding = reader.peekFieldEncoding();
            Object value = fieldEncoding.rawProtoAdapter().decode(reader);
            builder.addUnknownField(tag, fieldEncoding, value);
          }
        }
      }
      reader.endMessage(token);
      return builder.build();
    }

最后调用的方法builder.build()核心代码如下:

    @Override
    public MovieEntity build() {
      return new MovieEntity(version, params, images, sprites, audios, super.buildUnknownFields());
    }

可以看出,整个过程,就是通过类型的判断,然后构建出对应类型的一个自定义数据对象,也就是我们的MovieEntity对象。


整个大体的加载实现思路,可以简单地描述如下:
(1)传入资源url/路径,调用对应加载方法进行加载
(2)区分网络加载还是本地加载,网络加载会先走缓存逻辑,否则直接网络io进行加载
(3)通过加载方法,最后都会生成一个IO流,传入一个处理流的通用方法里面,进行MovieEntity对象构建,回调
(4)最后通过SVGADrawable的构造,设置给SVGAImageView对象,最后调用SVGAImageView对象的startAnimation()方法,即可显示动画。


上述就是svga文件,加载到显示的整体流程,至于其中的细节,如缓存key的生成,MovieEntity对象构造,可以拉官方module
的代码进行研究。

关于svga更多的源码阅读,将会在后面的文章一一描述,本次文章先到这里。

that’s all--------------------------------------------------------------------------------

猜你喜欢

转载自blog.csdn.net/motosheep/article/details/132978327