Lottie for Android:Json 動畫框架 Lottie 的使用及加載 zip 壓縮文件的方法

Json 動畫加載框架 Lottie,在網上已經有很多的相關文章了,但是版本都比較老,單獨加載 json 文件的還可以,涉及到加載 zip 壓縮文件的幾乎沒有,所以下面就稍稍列出常用的 json 動畫加載方式,再稍稍重點說一下加載 zip 壓縮文件的方法。

lottie-android github 地址

lottie 官網

本文 demo 時採用的是當時最新 lottie-android 版本:

dependencies {
  implementation 'com.airbnb.android:lottie:3.3.1'
}

地址是上面的 lottie-android github 地址:

json 動畫文件可以通過專業軟件 AE 轉換 gif 文件得來,當然求求 UI 大大也是可以有的。

1、在 xml 指定 json 動畫文件
// 放在raw文件夾
<com.airbnb.lottie.LottieAnimationView
    ... ...
    app:lottie_autoPlay="true"
    app:lottie_loop="true"
    app:lottie_rawRes="@raw/test" />
    
// 放在assets文件夾
<com.airbnb.lottie.LottieAnimationView
    ... ...
    app:lottie_autoPlay="true"
    app:lottie_loop="true"
    app:lottie_fileName="test.json" />
2、代碼中動態設置 json 動畫文件
// raw文件夾
mAnimationView.setAnimation(R.raw.test);
mAnimationView.setRepeatMode(LottieDrawable.REVERSE);//設置播放模式
mAnimationView.setRepeatCount(LottieDrawable.INFINITE);//設置重複次數
mAnimationView.playAnimation();

// assets文件夾
mAnimationView.setAnimation("test.json");
mAnimationView.setRepeatMode(LottieDrawable.REVERSE);//設置播放模式
mAnimationView.setRepeatCount(LottieDrawable.INFINITE);//設置重複次數
mAnimationView.playAnimation();
3、通過 string 加載 json 動畫
// 如果string內容是錯誤格式的json,app會直接崩潰,裏面是異步的,可以通過LottieAnimationView.setFailureListener監聽失敗
String jsonString = "{\"aaa\":[],\"bbb\":[]}";
mAnimationView.setAnimationFromJson(jsonString, null);
mAnimationView.setFailureListener(new LottieListener<Throwable>() {
    @Override
    public void onResult(Throwable result) {
        result.printStackTrace();
    }
});
mAnimationView.playAnimation();
4、加載網絡 json 動畫文件
// 如果url不存在,app會直接崩潰,裏面是異步的,可以通過LottieAnimationView.setFailureListener監聽失敗
mAnimationView.setAnimationFromUrl("https://xxx.com/test.json");
mAnimationView.setFailureListener(new LottieListener<Throwable>() {
    @Override
    public void onResult(Throwable result) {
        result.printStackTrace();
    }
});
mAnimationView.playAnimation();
5、加載 assets 文件夾中 json 文件和 images 配合的動畫
mAnimationView.setImageAssetsFolder("xxx/images");// 指定配合的images文件夾
mAnimationView.setAnimation("xxx/data.json");// json文件中要指定同級目錄中images名及圖片文件名
mAnimationView.playAnimation();

json 動畫可以單獨通過一個 json 文件加載動畫,動畫中可能有某部分是不變的,或者只做簡單的動畫效果(平移、縮放、旋轉 等等等等),如果只通過一個 json 文件去描述,那麼文件會很大,可能比要簡化的 gif 文件還大,但是,把其中某些部分製作成圖片, 通過 json 索引到指定的圖片,這樣做出來的文件數雖然多了,但是整體大小會小非常之多。

6、加載 assets 文件夾中的 zip 文件

流量在某些情況下會很費錢、費時,所以可以通過犧牲一點性能的方式換取流量的節省、時間的節省,這是很划算的,所以,可以把 json 動畫相關文件做壓縮下發,在拿到時解壓縮後使用。本點是放在 apk 包中,代碼中設置指定文件,Lottie 會幫我們解壓,下面再說網絡下發的用法。保持 apk 包的瘦小,也是對攻城獅的要求。

mAnimationView.setAnimation("test.zip");
mAnimationView.playAnimation();
7、在 xml 指定 zip 動畫文件
// 可以直接索引到assets中的zip文件,但是不能索引raw中的zip文件,運行會報錯
<com.airbnb.lottie.LottieAnimationView
    ... ...
    app:lottie_autoPlay="true"
    app:lottie_loop="true"
    app:lottie_fileName="test.zip" />
8、加載網絡上的 zip 文件

Lottie 可以通過設置網絡 json 文件和 zip 壓縮文件 url 加載特定動畫,上面有加載網絡 json 文件的用法,只要設置 url ,Lottie 會幫我們做剩下的工作。

String zipUrl = "https://xxx.com/test.zip";
mAnimationView.setAnimationFromUrl(zipUrl);
mAnimationView.setFailureListener(new LottieListener<Throwable>() {
    @Override
    public void onResult(Throwable result) {
        result.printStackTrace();
    }
});
mAnimationView.playAnimation();

但是,上面代碼中,在加載網路 zip 壓縮文件時,總是報下面的錯誤:

谷歌度娘找了幾圈,也沒有相應的解決方法,只能自己看源碼了,最後發現 Lottie 代碼中在判斷 zip 壓縮文件的 mime 類型時,出現以下的不匹配:


通過 python 讀取 zip 文件的 mime type:

所以,又谷歌度娘幾圈關於 application/zip 和 application/x-zip-compressed 的區別和轉換,應該是差不多的,可能是不同系統環境造成的差異,但是找得到 mime type 的讀取方法,就是找不到 application/zip 和 application/x-zip-compressed 之間的轉換方法,通過這種方法解決上面問題的路走不通了;那就偷懶一下,通過重寫相關類解決問題,但是發現各種 private,這條路也走不通,難道要我把整個 module 代碼拷出來“做大手術”;最後,通過乖乖讀源碼,還是找到了一小條“活路”,用下面的方式解決問題:

private void getZipFromUrl() {
    String zipUrl = "https://xxx.com/test.zip";
    if (!zipUrl.endsWith(".zip")) {
        return;
    }
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            try {
                HttpURLConnection connection = (HttpURLConnection) new URL(zipUrl).openConnection();
                connection.setRequestMethod("GET");
                connection.connect();
                if (connection.getErrorStream() != null || connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
                    return;
                }
                String contentType = connection.getContentType();
                if (contentType.contains("application/x-zip-compressed")) {
                    InputStream inputStream = connection.getInputStream();
                    // 設置zip流
                    ZipInputStream zipInputStream = new ZipInputStream(inputStream);
                    LottieTask<LottieComposition> task = LottieCompositionFactory.fromZipStream(zipInputStream, null);
                    task.addListener(new LottieListener<LottieComposition>() {
                        @Override
                        public void onResult(LottieComposition result) {
                            mAnimationView.setComposition(result);
                            mAnimationView.playAnimation();

                            try {
                                zipInputStream.close();
                                inputStream.close();
                                connection.disconnect();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    });
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    };
    ThreadUtil.runInWorkThread(runnable);
}

關鍵代碼是讀文件流和下面的代碼:

LottieTask<LottieComposition> task = LottieCompositionFactory.fromZipStream(zipInputStream, null);
task.addListener(new LottieListener<LottieComposition>() {
     @Override
     public void onResult(LottieComposition result) {
           mAnimationView.setComposition(result);
           mAnimationView.playAnimation();
     }
});

當然,如果 zip 壓縮文件的 mime type 本身就是 application/zip,或者有 application/zip 和 application/x-zip-compressed 的轉換方法,還是採用 Lottie 提供的 api 更穩健些。

最後還要注意一點,Lottie 獲取文件和設置繪製動畫用到很多異步,說不定什麼時候就崩一下,最好通過 LottieAnimationView.setFailureListener 去監聽失敗,做好後續處理:

mAnimationView.setFailureListener(new LottieListener<Throwable>() {
    @Override
    public void onResult(Throwable result) {
        result.printStackTrace();
    }
});

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章