fresh digitable

めんどくさかったなってことを振り返ったり振り返らなかったりするための記録

lottie-androidのgetCurrentKeyframe()の性能を改善するパッチが取り込まれた

github.com

モチベーション

BaseKeyframeAnimation.getCurrentKeyframe()は、アニメーションのプログレス(0から1の実数で表されるアニメーションの進捗度合い)の値にあうKeyframeを返すメソッド。このKeyframesetProgress()の際にキャッシュされている。処理のおおざっぱな流れは次の記事で書いた。

akihito104.hatenablog.com

getCurrentKeyframe()が呼ばれるたびに、キャッシュのヒット判定(現在のプログレスがKeyframeの時間幅に含まれているかチェックする)メソッドが呼ばれたり、リストから探す処理が走ったりする。何をするにもこれが呼ばれる。一度のメソッド呼び出しで何度も呼ばれることがある。

BaseKeyframeAnimationは0個以上のKeyframeを持っているのだが、たかだか1個しか持っていない場合には現在のキーフレームをキャッシュしたりプログレスが範囲に入っているかを判定する必要がない(0個の時も言うまでもない)。そこで、0個の場合、1個の場合、それより多い場合とに分けて不要な処理を行わないようにした。

何をしたのか

BaseKeyframeAnimationが持っているKeyframeのリストをラップしてそれぞれの場合に適した処理を行う静的な内部クラスを実装した。具体的には、

  • Keyframeが0個のときはなにもしない。
  • Keyframeが1個のときはキャッシュせず、キャッシュのヒット判定も行わない。
  • Keyframeが2個以上のときはこれまでと同じ処理をする。

Keyframeを1個しか持たないアニメーション部品が多いほど効果が出る。Keyframeが0個の時というのはほとんどないので効果もほとんどない。メモリ使用量が若干増える影響はあるものの、メソッド呼び出し回数が減ったため処理時間はせいぜい3割程度短くなった(アニメーションの構成による)。また処理の見通しが多少は良くなった。

抽象クラスの処理の変更はそれを継承しているクラスにも影響が出るかもしれないので難しかった。テストがちゃんとあってよかった。さらに最適化できそうだが効果がうすそうだったのでやらなかった。キャッシュの仕方に若干不満が残ってしまったのでもっといい形を思いつけば置き換えたい。

余談

じつは性能計測用のトレースメソッドをR8で消すほうが効果があるかもしれなかったりする