Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Compose の LazyColumn パフォーマンス改善で取り組んだこと
Search
Tomoya Miwa
June 14, 2022
Technology
2.5k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Compose の LazyColumn パフォーマンス改善で取り組んだこと
sample source:
https://github.com/tomoya0x00/ComposeLazyColumnSandbox
Tomoya Miwa
June 14, 2022
More Decks by Tomoya Miwa
See All by Tomoya Miwa
基礎から学ぶ大画面対応(Learning Large-Screen Support from the Ground Up)
tomoya0x00
0
8.6k
Re:VIEWで書いた「Compose で Android の edge-to-edge に対応する」をRoo Codeで発表資料にしてもらった
tomoya0x00
0
740
Compose 1.7のTextFieldはPOBox Plusで日本語変換できない
tomoya0x00
0
500
できる!ComposeでCollapsingToolbar
tomoya0x00
0
1.1k
ComposeのMutableStateってどうやってLocal Unit Testすれば良いの??
tomoya0x00
0
1.3k
意外と簡単?Navigation rail導入のお話
tomoya0x00
0
1.7k
Kotlin Coroutines Flow を触ってみた話し
tomoya0x00
2
910
Android for Carsのお話し
tomoya0x00
1
1.1k
熟成されたアプリのmulti module化(halfway)
tomoya0x00
2
1.1k
Other Decks in Technology
See All in Technology
LocalStack を使ったサーバーレスアプリケーション開発 / Serverless Development with LocalStack
kakakakakku
1
420
ハードウェアコンペでもAI駆動開発が進んでいる話
iotengineer22
1
700
会社説明資料
persolserverworks
0
9.7k
Railsで挑む大量データ永続化 〜600億件を永続化するための設計とボトルネックとの戦い〜
occhi
0
170
スキマバイトという雇用形態は存在しないので、雇用期間1日のアルバイト契約を事業者とワーカーが結ぶ手続きを支えるのがタイミーなんです
akitoshiga
0
150
AIに攻撃される前に、AIに攻撃させる
tsuchikazu
0
170
UniFi(ユニファイ)AIカメラの現場活用
ludicmind
1
420
分析の民主化を支えるメタデータ整備の実践
kakehashi
PRO
4
1.3k
組み立てて楽しむ AWS Blocks 入門
kmiya84377
0
230
Loop Engineering これくらいでいい
mikanichinose
0
230
Loop Engineering, beyond prompt, context, and harness engineering
glaforge
0
100
事業活動を AI Ready にする攻めと守りのデータエンジニアリング / data-engineering-for-ai-ready-business
pei0804
7
2.7k
Featured
See All Featured
Paper Plane
katiecoart
PRO
5
54k
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.4k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
250
1.3M
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
3k
Reality Check: Gamification 10 Years Later
codingconduct
0
2.3k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
7k
How to Talk to Developers About Accessibility
jct
2
570
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
780
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
400
Prompt Engineering for Job Search
mfonobong
0
510
Dominate Local Search Results - an insider guide to GBP, reviews, and Local SEO
greggifford
PRO
0
360
Ethics towards AI in product and experience design
skipperchong
2
420
Transcript
Compose の LazyColumn パフォーマンス改善で取り組 んだこと 2022/06/14 Engineer LT#1 Android tomoya0x00
1
About me tomoya0x00 Twitter, GitHub Android U-NEXT Co., Ltd. 2
今回のLTが(もしかしたら)役に立つかもしれない? LazyColumnって、RecyclerViewよりもパフォーマンス良いんだよね? Composeのパフォーマンス問題って、Releaseビルドにしたら解決するんでしょ? 最新技術のComposeなんだから、従来のAndroid Viewよりもパフォーマンスで悩むこと は少ないはず! 3
お話しすること LazyColumnを気軽に使ったらパフォーマンス問題に直面し、 なんとかNexus 7 2013という低スペック端末でもある程度使えるレベルにした話。 4
目次 パフォーマンスに絶望した話 パフォーマンス問題に対する考察 対策その1: Glideを使ってみる 対策その2: さらにインスタンス生成を減らす 対策その3: 描画を遅延させてスキップ可能とする これまでのような対策の前に確認しておくと良い事
他にも効果がありそうな事 まとめと感想 5
パフォーマンスに絶望した話 6
まずは動画をご覧下さい 7
8
パフォーマンスに絶望した話 Nexus 7 2013で動かしました アニメーションGIFのフレームレートは30fpsです アニメーションGIFだからカクカクしているわけではありません Releaseビルドです もちろん、minifyEnabled true LazyRow
in LazyColumnで、各itemではCard内でCoilにより画像表示しているだけのシ ンプルなアプリです ちなみに、RecyclerViewだとさくさく動きます ソースコードのリンク: MainContentA 9
このままだとCompose化の夢が絶たれてしまう・・・ 10
パフォーマンス問題に対する考察 11
logcat GCのログが多いような気がする Background partial concurrent mark sweep GC freed 12609(781KB)
AllocSpace objects, 9(180KB) LOS objects, 39% free, 21MB/35MB, paused 5.401ms total 73.333ms Background partial concurrent mark sweep GC freed 9126(463KB) AllocSpace objects, 3(156KB) LOS objects, 33% free, 31MB/47MB, paused 7.476ms total 48.278ms Background partial concurrent mark sweep GC freed 122448(9MB) AllocSpace objects, 0(0B) LOS objects, 33% free, 24MB/36MB, paused 3.021ms total 171.936ms Background partial concurrent mark sweep GC freed 34312(1960KB) AllocSpace objects, 1(20KB) LOS objects, 33% free, 23MB/35MB, paused 1.861ms total 110.321ms Background partial concurrent mark sweep GC freed 302696(15MB) AllocSpace objects, 5(124KB) LOS objects, 36% free, 28MB/44MB, paused 2.227ms total 140.014ms Background partial concurrent mark sweep GC freed 95715(7MB) AllocSpace objects, 4(80KB) LOS objects, 33% free, 24MB/36MB, paused 1.861ms total 106.079ms ... 12
パフォーマンス問題に対する考察 Nexus 7 2013という(今となっては)低スペック端末にとっては、 インスタンス生成が走りすぎているのかも知れない。 CoilのAsyncImageは色々インスタンス生成している 各AsyncImageごとにcoroutineを起動しているっぽい? その他、色々インスタンス生成している Modifierもメソッドチェーンする度に新しいインスタンスを生成しているっぽい 確かにAsyncImage無しだとかなりパフォーマンスが改善したので、
まずはCoil使うのをやめてみる。 ※ 一般的なケースでは、Coilがボトルネックになることは無いとおもいます!! 13
対策その1: Glideを使ってみる 14
対策その1: Glideを使ってみる Glide版の画像読み込みComposableをつくってみた。 以前はaccompanistでComposable版が提供されていた実績がある 昔からあるライブラリだから、使用するリソース的にも優しいはず 確かにパフォーマンスは改善したけど、まだカクついてる。 ソースコードのリンク: MainContentBSimpleAsyncImage 15
対策その2: さらにインスタンス生成を減らす 徹底的にインスタンス生成を減らす。 MaterialのCard使うのをやめる 内部で色々インスタンス生成しているため 一度つくったModifierはキャッシュする ソースコードのリンク: MainContentC 16
Modifierのキャッシュ class ModifierCacheHolder { private val map = mutableMapOf<String, Modifier>()
@SuppressLint("ModifierFactoryExtensionFunction", "ComposableModifierFactory") @Composable fun getOrCreate( tag: String, creator: @Composable () -> Modifier, ): Modifier = map[tag] ?: creator.invoke().also { map[tag] = it } } ソースコードのリンク: ModifierCacheHolder 17
Modifierのキャッシュ val modifierCacheHolder = remember { ModifierCacheHolder() } Column( modifier
= modifierCacheHolder.getOrCreate(tag = "MainRowRoot") { Modifier.padding(top = 8.dp) }, ) { ... } 18
Modifierのキャッシュ 基本的にModifierのインスタンスはStableなので、使い回しても大丈夫・・・なはず ただし、あんまり自信は無し 今のところ目に見えて不具合は起きていないので、たぶん大丈夫? ただし、Modifier.clickable()のインスタンスはキャッシュしちゃダメ 最初にセットしたクリックリスナーが使い回されてしまう clickable()の手前までのModifierのインスタンスなら、キャッシュしてOK 19
改善の成果をご覧下さい 20
21
残った課題に対する考察 22
残った課題に対する考察 高速なスクロールは、とてもカクつく 各行の描画にかかる時間が、そもそも1フレームを超えていそう そもそも高速スクロールで一瞬しか表示されないなら、描画をサボって良いのでは? 描画自体を遅延させてスキップ可能にしてみてはどうだろう? ソースコードのリンク: MainContentD 23
対策その3: 描画を遅延させてスキップ可能とする 24
対策その3: 描画を遅延させてスキップ可能とする @Composable fun LazyBox( modifier: Modifier = Modifier, delayMilliSec:
Long, content: @Composable BoxScope.() -> Unit, ) { Box( modifier = modifier, ) { var showContent by remember { mutableStateOf(false) } LaunchedEffect(Unit) { withContext(Dispatchers.Default) { delay(delayMilliSec) showContent = true } } if (showContent) content.invoke(this) } } ソースコードのリンク: LazyBox 25
対策その3: 描画を遅延させてスキップ可能とする LazyBox( delayMilliSec = 10, placeHolder = { Spacer(
modifier = modifierCacheHolder.getOrCreate(tag = "MainRowPlaceHolder") { Modifier.size(8.dp * 2 + 120.dp * 9f / 16) }, ) }, ) { LazyRow { items( items = data.rowIds, key = { it }, ) { rowId -> MainItemD( modifierCacheHolder = modifierCacheHolder, text = "${data.columnId}_$rowId", ) } } } 26
最終的にどうなったか 27
28
これまでのような対策の前に確認しておくと良い事 29
これまでのような対策の前に確認しておくと良い事 Compose Compiler Metricsのチェック https://github.com/androidx/androidx/blob/androidx- main/compose/compiler/design/compiler-metrics.md 特にListはそのままだとStable扱いにならないので要注意です 対策の例としては、@Immutableなdata classで包む Jetpack
ComposeのComposable関数の引数に別のモジュールのクラスを使うときの注 意点 https://qiita.com/takahirom/items/6907e810d3661e19cfcf 30
他にも効果がありそうな事 31
他にも効果がありそうな事 Compose 1.2のcontentType LazyListでRecyclerViewのようにComposableをもっと効率的に再利用するための もの ただし、今回の例に適用してもあまり効果が感じられなかった 使い方が悪い?ちゃんと計測したら、実は改善されているのかも? Baseline Profiles あらかじめよく使うパスを計測しておくことで、それらのバイトコードからコンパ
イルしてもらう、というもの? 効果が期待できそうだけど、まだ試せておらず 32
まとめと感想 33
まとめと感想 正直、やり過ぎたと思ってます たぶん、通常のアプリだとどうしても必要な場合だけLazyBoxいれる、ぐらいで良 いと思う そもそもBaseline Profilesで事足りるかも知れない 今時、Nexus 7 2013は流石に考慮しなくて良いと思う ただし、特にお手頃価格のタブレットはパフォーマンスが控えめな事もあるので、
実機で動作確認してみた方が良い 34