• 关于安卓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)
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    核心代码,就是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
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    可以看出,这里对传入对象的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();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

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

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

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


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


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

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

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

  • 相关阅读:
    C语言典范编程
    双指针算法
    CSDN页面左上角出现红色“不安全 | https” ,并且把鼠标放在上面的头像和消息时无法下拉菜单
    【Vue】Axios取消请求
    AntPathMatcher路径匹配器,Ant风格的URL
    ESP32 (新建工程文件)-Vscode IDF新建工程(10)
    Fooocus框架代码分析
    Axios使用
    Lombok
    windows局域网传文件5种常用方法
  • 原文地址:https://blog.csdn.net/motosheep/article/details/132978327