1. 程式人生 > >lottie載入動畫,第一次有延遲問題

lottie載入動畫,第一次有延遲問題

lottie是airbnb推出的一個直接將AE工程轉化為動畫的工具。

ae.project-->data.json-->LottieComposition-->Lottie動畫

之前做一個比較複雜的動畫,花了兩天時間都在畫各種弧,計算運動軌跡等等。感覺我不是在程式設計,我是在算數學。

上lottie的過程,花了半天時間調AE動畫,因為設計師的電腦上裝外掛沒裝成功。所以AE轉json檔案的過程都拋給了開發。

原本做第一個動畫就花了2天,現在4個動畫,我幾分鐘全搞定了。設計想怎麼改,就怎麼改,我無非是替換一下json檔案就可以了,真是痛快。在設計眼皮下,一畫素一畫素調UI,我覺得是最浪費時間的事。

說說碰到的這個問題吧:

場景:第一開啟Activity的時候,動畫過了0.3s才顯示出來,好點的手機不會,老點的手機就比較明顯。

分析了一下原始碼

public void setAnimation(@RawRes final int animationResId, final CacheStrategy cacheStrategy) {
    this.animationResId = animationResId;
    animationName = null;
    if (RAW_RES_WEAK_REF_CACHE.indexOfKey(animationResId) > 0) {
      WeakReference<LottieComposition> compRef = RAW_RES_WEAK_REF_CACHE.get(animationResId);
      LottieComposition ref = compRef.get();
      if (ref != null) {
        setComposition(ref);
        return;
      }
    } else if (RAW_RES_STRONG_REF_CACHE.indexOfKey(animationResId) > 0) {
      setComposition(RAW_RES_STRONG_REF_CACHE.get(animationResId));
      return;
    }

    clearComposition();
    cancelLoaderTask();
    compositionLoader = LottieComposition.Factory.fromRawFile(getContext(), animationResId,
        new OnCompositionLoadedListener() {
          @Override public void onCompositionLoaded(LottieComposition composition) {
            if (cacheStrategy == CacheStrategy.Strong) {
              RAW_RES_STRONG_REF_CACHE.put(animationResId, composition);
            } else if (cacheStrategy == CacheStrategy.Weak) {
              RAW_RES_WEAK_REF_CACHE.put(animationResId, new WeakReference<>(composition));
            }

            setComposition(composition);
          }
        });
  }

setAnimation的過程,會先從cache中取,如果沒有就自己構造一個Composition,composition中包含了所有的動畫描述資訊。

所以問題就出在了composition的構造

/**
     * Loads a composition from a json reader.
     * <p>
     * ex: fromInputStream(context, new FileInputStream(filePath), (composition) -> {});
     */
    public static Cancellable fromJsonReader(
        JsonReader reader, OnCompositionLoadedListener listener) {
      AsyncCompositionLoader loader = new AsyncCompositionLoader(listener);
      loader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, reader);
      return loader;
    }

不斷跟進LottieComposition.Factory中的fromRawFile()方法,最終發現AsyncCompositionLoader,問題就出來了,從ae產物json動畫描述檔案的解析過程是一個非同步的過程,自然會影響到動畫的第一開啟的速度。

對於起步時間敏感的動畫,有沒有同步的方法給我們調一調呢?

搜了下sync關鍵字,果然有。

public static LottieComposition fromJsonSync(JsonReader reader) throws IOException {
      return LottieCompositionParser.parse(reader);
    }

然後我們再倒著找最外層封裝好的方法:

/**
     * Loads a composition from a file stored in /assets.
     */
    public static Cancellable fromAssetFileName(
        Context context, String fileName, OnCompositionLoadedListener listener) {
      InputStream stream;
      try {
        stream = context.getAssets().open(fileName);
      } catch (IOException e) {
        throw new IllegalArgumentException("Unable to find file " + fileName, e);
      }
      return fromInputStream(stream, listener);
    }

可以可以,就是這個了,把原來xml中的data.json複製一份放在asset目錄下,

LottieAnimationView lottieAnimationView = findViewById(R.id.animation_view);
        LottieComposition composition = LottieComposition.Factory.fromFileSync(this,"data.json");
        lottieAnimationView.setComposition(composition);

執行一下,OK,延遲消失了。

當然非同步載入有非同步的好處。大家可以根據自己的需要來選擇同步非同步,或者是否需要CacheStrategy來做強快取,或者弱快取,提高載入的速度。