$30 off During Our Annual Pro Sale. View Details »

実例から学ぶJetpack Composeのパフォーマンス改善

Mori Atsushi
October 06, 2022

実例から学ぶJetpack Composeのパフォーマンス改善

Jetpack ComposeはAndroid Viewシステムの教訓を経て、多くのケースで優れたパフォーマンスを発揮します。一方で、いつの間にかパフォーマンスが低下している経験をした人も多いのではないでしょうか?特にアニメーションの表現や、スクロールやドラッグの操作によってUIを切り替える際によく問題が発生します。これらは、必要以上の広範囲で高速に更新処理が行われることに起因します。

より良いパフォーマンスを得るには、Jetpack ComposeのUI更新の仕組みを理解し、状況に応じて対処していく必要があります。このセッションでは実例をもとに、パフォーマンス低下の原因、計測方法、改善方法について解説を行います。

DroidKaigi: https://droidkaigi.jp/2022/timetable/364831
Video: https://youtu.be/_kIkc4IBLHI
Sample code: https://github.com/Mori-Atsushi/compose-performance

Mori Atsushi

October 06, 2022
Tweet

More Decks by Mori Atsushi

Other Decks in Technology

Transcript

  1. .PSJ"UTVTIJ גࣜձࣾαΠόʔΤʔδΣϯτגࣜձࣾ$ZCFS;  ࣮ྫ͔ΒֶͿ 
 +FUQBDL$PNQPTFͷύϑΥʔϚϯεվળ %SPJE,BJHJ +FUQBDL$PNQPTF

  2. 株式会社サイバーエージェント 
 株式会社CyberZ OPENREC.tv 2019年度 未踏スーパークリエータ Mori Atsushi Twitter: @at_sushi_at

  3. We Love 
 Jetpack Compose! Android向けの新しいUIフレームワーク 2019年 Google I/Oにて発表 2021年7⽉

    Stable
  4. パフォーマンス改善 ᶃNFBTVSF ᶄNFBTVSF ᶅNFBTVSF ᶆNFBTVSF ᶇNFBTVSF ᶃNFBTVSF ᶄNFBTVSF ᶅNFBTVSF "OESPJE7JFX

    +FUQBDL$PNQPTF 7JFX(SPVQ ਌$PNQPTBCMF 7JFX 7JFX ࢠ$PNQPTBCMF ࢠ$PNQPTBCMF ඞͣҰ౓ͣͭͷΈ͔͠ܭଌ͞Εͳ͍ ਌ࢠΛԿ౓΋ܭଌ͢Δ৔߹͕͋Δ
  5. パフォーマンスの低下 Jetpack Composeのほうが 
 基本的にはパフォーマンスが良い ⼀⽅、予期せずパフォーマンスが落ちることがある スクロールやドラッグがもっさりしている アニメーションでフレーム落ちしている 操作に対する反応が遅れる 🐢

  6. 今回のゴール Jetpack Composeで陥りやすい 
 パフォーマンス低下を実例とともに理解/改善する 1. パフォーマンスの調査⽅法 2 . derivedStateOfを使う

    3 . skippableにする 4 . Stateの監視場所を変える 🚀
  7. パフォーマンスの調査⽅法 1

  8. 買い物リストアプリ 購⼊予定のアイテムを追加、管理できる 全体的に動作がもっさり… IUUQTHJUIVCDPN.PSJ"UTVTIJDPNQPTFQFSGPSNBODF

  9. εΫϩʔϧҐஔ͸ ϦετͷҰ൪্͔ Ұ൪্Ͱͳ͍ͱ͖͸ "QQ#BSʹӨΛ͚ͭΔ εΫϩʔϧ͕͔ͭ͘͘ ഒ଎

  10. 早すぎる最適化を避ける க໋తͳ ύϑΥʔϚϯε՝୊ ίʔυͷՄಡੑ Өڹͷখ͍͞ ύϑΥʔϚϯε՝୊ Өڹͷͳ͍ ύϑΥʔϚϯε՝୊ ॏཁ౓͕ߴ͍ ॏཁ౓͕௿͍

    最初から最適化を⽬指すのは、コードの⾒通しが悪化したり、 
 無駄なコストになる パフォーマンスの問題が⽣じた際に必要な対応を⾏う
  11. ボトルネックを探す 闇雲にコードを変更しても、解決に⾄る可能性は低く、 
 かえって問題を⼤きくする ボトルネックを発⾒し、解消することが重要である $PNQPTBCMF $PNQPTBCMF $PNQPTBCMF  $PNQPTBCMF

     Composable 2 に時間がかかってるのに、1や3,4を頑張って変更しても、ほとんど変化はない
  12. パフォーマンス問題が 
 ⽣じたら? 1. リリースビルドで確認する 2. 不要なRecomposeがないか確認する 3 . Pro

    fi lerで詳細を⾒る 🏃
  13. 1. リリースビルドで 
 1. 確認する Jetpack Composeはデバッグビルドと 
 リリースビルドで⼤きくパフォーマンスが異なる 不要なコードを削除するR

    8 コンパイラも利⽤する (デフォルトで有効) 🛠 IUUQTEFWFMPQFSBOESPJEDPNKFUQBDLDPNQPTFQFSGPSNBODF
  14. 2. 不要なRecomposeがないか確認する $PNQPTBCMF ᶄ஋͕มԽ ᶃϘλϯ͕ΫϦοΫ ᶅ࠶࣮ߦ -FBWF &OUFS 3FDPNQPTF IUUQTEFWFMPQFSBOESPJEDPNKFUQBDLDPNQPTFMJGFDZDMF

  15. ログを仕込む 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF

    4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 4IPQQJOH-JTU1BHFDPNHJUIVCNPSJBUTVTIJQFSGPSNBODF%SFDPNQPTF 3FDPNQPTFຖʹ ϩάग़ྗ ࿈ଓతʹݺͼग़͞Ε͍ͯΔ
  16. Layout Inspector Compose 1 . 2 以降とAndroid Studio Dolphin以降を使うと Recompose数を確認できる

    IUUQTEFWFMPQFSBOESPJEDPNTUVEJPSFMFBTFTMJDPNQPTFDPVOUFS 4IPX3FDPNQPTJUJPO 
 $PVOUTΛ༗ޮʹ͢Δ
  17. 3FDPNQPTF਺ 3FDPNQPTF͕εΩοϓ͞Εͨ਺ େྔʹSFDPNQPTF͞Ε͍ͯΔ

  18. 3 . Pro fi lerで詳細を⾒る アプリを実⾏中のデバイスのCPUやメモリの状況を確認できる IUUQTEFWFMPQFSBOESPJEDPNTUVEJPQSP fi MFBOESPJEQSP fi

    MFS
  19. $BMMTUBDL4BNQMF3FDPSEJOH େྔʹ3FDPNQPTF͕ ݺ͹Ε͍ͯΔ

  20. ϦϦʔεϏϧυͰ΋1SPGJMFՄೳʹ͢Δ "OESPJE.BOJGFTUYNM

  21. 6*δϟϯΫ͕ൃੜ͍ͯ͠Δ 4ZTUFN5SBDF3FDPSEJOH SFDPNQPTFʹ ͕͔͔͍࣌ؒͬͯΔ

  22. Composition Tracing Compose 1 . 3 (beta)以降とAndroid Studio Flamingo(preview)を 


    使うとリリースビルドでも確認できる! IUUQTNFEJVNDPNBOESPJEEFWFMPQFSTKFUQBDLDPNQPTFDPNQPTJUJPOUSBDJOHFDCBFB 4IPQQJOH*UFN3PX͕ େྔʹݺ͹Ε͍ͯΔ 4ZTUFN5SBDF3FDPSEJOH
  23. derivedStateOfを使う 2

  24. গ͠Ͱ΋εΫϩʔϧ͞ΕΔ౓ʹɺ ࠶ܭࢉ͞Ε͍ͯΔ

  25. ܭࢉ݁Ռ͕มΘͬͨͱ͖ͷΈ 
 3FDPNQPTF͢Δ SFNFNCFS͸ඞਢ ഒ଎ ͔͖͕ͭ͘ݮͬͨ

  26. skippableにする 3

  27. ϘλϯͰ਺ྔͷ૿ݮ͕Մೳ ߋ৽ͨ͠ΞΠςϜҎ֎΋ 3FDPNQPTF͞Ε͍ͯΔ ഒ଎

  28. -B[Z$PMVNO *UFN -B[Z$PMVNO *UFN $IBOHFE 4LJQ Item: 1 を変更 ⼊⼒に変更がなければスキップする

    4LJQ 3FDPNQPTF *UFN *UFN *UFN 3FDPNQPTF
  29. スキップの条件 条件1: すべての⼊⼒が安定している → 全く変更がされない(Immutable)か、 
 → 変更時にCompositionに通知される 条件2:すべての⼊⼒で変更がない →

    すべての⼊⼒でequalsの結果がtrue 🚅
  30. スキップの条件 条件1: すべての⼊⼒が安定している → 全く変更がされない(Immutable)か、 
 → 変更時にCompositionに通知される 条件2:すべての⼊⼒で変更がない →

    すべての⼊⼒でequalsの結果がtrue 🚅
  31. 安定している型(抜粋) ϓϦϛςΟϒ஋ܕ จࣈྻ ϥϜμࣜ ͦΕΒͰߏ੒͞ΕΔෆมͳDMBTT

  32. 安定していない型(抜粋) -JTU4FU ՄมͳΫϥε $PNQPTFΛ࢖͍ͬͯͳ͍ ଞϞδϡʔϧϥΠϒϥϦͷΫϥε 5ISPXBCMF΍%BUF

  33. Compose Compiler Metrics Composableがスキップ可能か確認できるツール ΦϓγϣϯΛ௥Ճ CVJMEDPNQPTF@NFUSJDTʹ Ϩϙʔτ͕ग़ྗ͞ΕΔ IUUQTEFWFMPQFSBOESPJEDPNKFUQBDLDPNQPTFMJGFDZDMF

  34. ҆ఆ͍ͯ͠ͳ͍ εΩοϓෆՄ ҆ఆ͍ͯ͠ͳ͍

  35. ΞϊςʔγϣϯͰෆมͰ ͋Δ͜ͱΛ໌ࣔ

  36. ಺෦ʹ.VUBCMF4UBUF౳ͷՄม஋͕͋Δ৔߹͸ 4UBCMFΞϊςʔγϣϯΛར༻͢Δ ಺෦ͷ஋͕มΘΒͳ͍ͱ͖͸ *NNVUBCMFΛ࢖͏

  37. 案1 依存関係を追加して @Immutable / @Stable 
 を付与する モデルが別モジュールにある場合 案2 View⽤のmodelを別で作成し、

    マッピングする 案3 @Immutable / @Stableを 
 つけたHolder classでwrapする
  38. すべてをskippableに? 💡 すべてのComposbleをskippableにするのは、 
 早すぎる最適化のように感じる 同じ引数で再び呼び出されることのない Composableをskippableにするのは無意味である

  39. スキップの条件 条件1: すべての⼊⼒が安定している → 全く変更がされない(Immutable)か、 
 → 変更時にCompositionに通知される 条件2:すべての⼊⼒で変更がない →

    すべての⼊⼒でequalsの結果がtrue 🚅
  40. ຖճ-BNCEB͕ࣜ࠶ੜ੒͞Εɺ มߋ͕͋ΔͱΈͳ͞ΕΔ

  41. Lambda式の再⽣成 ࠶ར༻͞ΕΔ ࠶ੜ੒͞ΕΔ Lambda式中で安定でないクラスを参照していると、 
 recompose毎にLambda式が再⽣成される IUUQTNVMUJUISFBEFETUJUDI fi YDPNCMPHKFUQBDLDPNQPTFSFDPNQPTJUJPO

  42. Lambda式の再⽣成を防ぐ 案2 Lambda式を明⽰的に 
 rememberする 案3 関数参照を渡す 案1 ViewModelに@Stableを追加

  43. ഒ଎ ߋ৽͞ΕͨΞΠςϜͷΈ SFDPNQPTF͞ΕΔ

  44. Stateの監視場所を変える 4

  45. εϥΠμʔͷ஋ Ҿ਺Ͱঢ়ଶΛड͚औΔ ഒ଎ εϥΠμʔ͕ॏ͍ͨ

  46. State Hosting 4IPQQJOH-JTU1BHF "EE%JBMPH 4MJEFS 3FDPNQPTF 3FDPNQPTF 3FDPNQPTF 状態は呼び出し元で管理し、 Single

    Source of Truthを実現する ⼦をrecomposeするために、 すべての親がrecomposeされている IUUQTEFWFMPQFSBOESPJEDPNKFUQBDLDPNQPTFTUBUFTUBUFIPJTUJOH
  47. Stateの監視とrecomposeの範囲 4UBUFͰड͚औΔ ͜͜Ͱ؂ࢹ ͜͜Ͱ؂ࢹ

  48. -BNCEBࣜͰड͚औΔ 他の記述⽅法 ಠࣗ4UBUFΛ༻ҙ͢Δ

  49. 4UBUFͰอ࣋͢Δ ഒ଎ վળʂ

  50. Stateの取得を遅らせる 🛫 必要になるまでStateの値の取得を遅らせることで、 必要最⼩限のスコープで再実⾏ができる skippableの対応のほうが体感効果が⾼い スクロール、ドラッグ、アニメーション等、 
 毎フレーム値が変わる場合におすすめ

  51. まとめ $PNQPTJUJPO パフォーマンスはボトルネックを発⾒し、改善を⽬指す よくある修正⽅法 - derivedStateOfを使う - skippableにする - Stateの監視場所を変える

    パフォーマンスの調査⽅法 - 不要なrecomposeが - ないか確認する - Pro fi lerで詳細を⾒る