Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
JankStats LibraryでJankを検出しよう / Detecting Jank w...
Search
KeitaTakahashi
July 11, 2023
Technology
1.9k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
JankStats LibraryでJankを検出しよう / Detecting Jank with JankStats Library
KeitaTakahashi
July 11, 2023
More Decks by KeitaTakahashi
See All by KeitaTakahashi
誰と働くか / Who I work with
tkhskt
1
190
ZOZOTOWN AndroidへのJetpack Composeの導入 / Introducing Jetpack Compose for ZOZOTOWN Android
tkhskt
1
12k
Other Decks in Technology
See All in Technology
20260619 私の日常業務での生成 AI 活用
masaruogura
1
230
Agile and AI Redmine Japan 2026
hiranabe
3
290
AIチャット検索改善の3週間
kworkdev
PRO
2
140
人材育成分科会.pdf
_awache
4
300
LayerX コーポレートエンジニアリング室におけるサプライチェーンセキュリティへの取り組み / Supply Chain Security at LayerX Corporate Engineering
yuyatakeyama
2
680
【NRUG vol.18】KubernetesにおけるNew Relicデータ取得量削減の考え方
nrug_member
0
170
脆弱性対応、どこで線を引くか
rymiyamoto
1
420
脱SaaS!FDEを支えるプロビジョニングと分離設計
knih
0
240
SONiCで構築・運用する生成AI向けパブリッククラウドネットワーク ~実装編~
sonic
0
280
あなたの知らないPDFのアクセシビリティ
lycorptech_jp
PRO
0
220
アジャイルな経理と Claude Code と経営の未来
kawaguti
PRO
3
160
2026 TECHFRESH 畢業分享會 - AI-Native 重塑軟體工程與虛擬講師
line_developers_tw
PRO
0
1.3k
Featured
See All Featured
What’s in a name? Adding method to the madness
productmarketing
PRO
24
4.1k
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
2
400
We Are The Robots
honzajavorek
0
250
Agile Actions for Facilitating Distributed Teams - ADO2019
mkilby
0
210
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
Balancing Empowerment & Direction
lara
6
1.2k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
254
22k
Writing Fast Ruby
sferik
630
63k
Building Better People: How to give real-time feedback that sticks.
wjessup
370
20k
Designing for Performance
lara
611
70k
Have SEOs Ruined the Internet? - User Awareness of SEO in 2025
akashhashmi
0
370
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.5k
Transcript
JankStats LibraryでJankを 検出しよう 2023/07/11 ZOZO Tech Meetup - iOS/Android 株式会社ZOZO
ZOZOTOWN開発本部 ZOZOTOWNアプリ部 Android2ブロック Androidテックリード 高橋啓太 Copyright © ZOZO, Inc. 1
© ZOZO, Inc. 2 株式会社ZOZO ZOZOTOWN開発本部 ZOZOTOWNアプリ部 Android2ブ ロック Androidテックリード
高橋 啓太 2020年新卒入社
© ZOZO, Inc. 話すこと 3 • JankStats Libraryの基本的な情報 • Jankとは
• Jank検出ツール • JankStats Libraryの基本的な使用方法
© ZOZO, Inc. JankStats Libraryの基本的な情報 4 • アプリのレンダリングパフォーマンスに関する情報を取得することができる ◦ 後述する「Jank」を検出可能
• FrameMetrics APIやOnPreDrawListenerの上に構築されている • 2023/07/11時点ではApril 5, 2023リリースの1.0.0-alpha04が最新 • android/nowinandroidにも入っている Metrics | Jetpack | Android Developers: https://developer.android.com/jetpack/androidx/releases/metrics android/nowinandroid | GitHub: https://github.com/android/nowinandroid
© ZOZO, Inc. 5 Jankとは
© ZOZO, Inc. Jankとは 6 遅いレンダリング | App quality |
Android Developers: https://developer.android.com/topic/performance/vitals/render?hl=ja • ユーザーがスムーズにアプリを操作するためには、各デバイスで決められたリフ レッシュレートを達成できるようフレーム生成時間を維持することが必要 ◦ 一般的には60fpsを達成することが必要 • なんらかの理由でフレームがスキップされ、アプリの動作がスムーズでなくなるこ とを「Jank(ジャンク)」と呼ぶ
© ZOZO, Inc. Jankとは - ANR等との関係性 7 ジャンクのトラッキング | App
quality | Android Developers: https://developer.android.com/topic/performance/vitals/tracking_jank?hl=ja 遅いフレーム フリーズしたフレーム ANR 表示に要する時間 16ms~700ms 700ms~5s 5sより長い ユーザーが知覚できる現象の例 リストのスクロールがカクつく 画面遷移時がスムーズではない 画面をタップしても5秒以上反応がな い
© ZOZO, Inc. Jankとは - ANR等との関係性 8 → これらは全てJankに分類される 遅いフレーム
フリーズしたフレーム ANR 表示に要する時間 16ms~700ms 700ms~5s 5sより長い ユーザーが知覚できる現象の例 リストのスクロールがカクつく 画面遷移時がスムーズではない 画面をタップしても5秒以上反応がな い ジャンクのトラッキング | App quality | Android Developers: https://developer.android.com/topic/performance/vitals/tracking_jank?hl=ja
© ZOZO, Inc. Jankとは - ANR等との関係性 9 → これらは全てJankに分類される →
Jankの検出・修正は、快適な操作感を維持するために重要 遅いフレーム フリーズしたフレーム ANR 表示に要する時間 16ms~700ms 700ms~5s 5sより長い ユーザーが知覚できる現象の例 リストのスクロールがカクつく 画面遷移時がスムーズではない 画面をタップしても5秒以上反応がな い ジャンクのトラッキング | App quality | Android Developers: https://developer.android.com/topic/performance/vitals/tracking_jank?hl=ja
© ZOZO, Inc. 10 Jank検出ツール
© ZOZO, Inc. Perfetto 11 • ADBを介して、Android端末からフレームの情報を含むパフォーマンス情報を取得 するツール • 取得したパフォーマンス情報はPerfetto
UIで可視化して分析可能 • ZOZOTOWNではスクロール時のJankを分析する際に使用した Perfetto: https://perfetto.dev/ perfetto | Android Developers: https://developer.android.com/studio/command-line/perfetto?hl=ja Perfettoを用いたAndroidアプリのボトルネックの特定とその改善 | ZOZO TECH BLOG: https://techblog.zozo.com/entry/android-performance-improvement-with-perfetto
© ZOZO, Inc. AndroidStudio Profiler 12 • Chipmunk以降のAndroid StudioではProfilerでJankを検出可能 ◦
Android12以降の端末が必要 Android Developers Japan Blog: Android Studio の CPU profiler で UI のジャンクを検出する https://android-developers-jp.googleblog.com/2022/07/spot-your-ui-jank-using-cpu-profiler-in-android-studio.html
© ZOZO, Inc. JankStats Library 13 • androidx.metrics.performance • 下記の機能を提供する
◦ Jankの識別 ▪ Jankの発生タイミングに関する情報を取得できる ◦ Jankが発生した時点でのアプリの状態取得 ▪ Jankが発生した際にユーザーがどのような操作をしていたかを確認できる ◦ 結果のレポート ▪ フレームに関する情報(完了にかかった時間など)を取得できる
© ZOZO, Inc. JankStats Libraryの何が良いのか? 14 • 開発環境でのJank検出はPerfettoやAndroid StudioのProfilerで十分可能 •
しかし、本番環境(ユーザーの手元)で実際に発生しているJankを検出することは できない • JankStats Libraryをプロダクトに導入し、データを収集することで、本番環境で発 生しているJankの原因が分析可能になる ◦ 取得したデータの保存やデータを送信する仕組みは提供されていない ※「保存とアップロードに関する詳細情報は、JankStats API アルファ版リリースでは提供されません」 とあるので将来的になんらかのサポートが追加される可能性はある https://developer.android.com/topic/performance/jankstats?hl=ja
© ZOZO, Inc. 15 JankStats Libraryの基本的な使用方法
© ZOZO, Inc. 16 JankStats Libraryの基本的な使用方法 ※alpha版のため今後APIが変更される場合があります
© ZOZO, Inc. 導入 17 implementation "androidx.metrics:metrics-performance:1.0.0-alpha04" 何はともあれimplementation
© ZOZO, Inc. class MainActivity : ComponentActivity() { private lateinit
var jankStats: JankStats override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { ... } jankStats = JankStats.createAndTrack(window) { frameData -> if (frameData.isJank) { // Jankと判定されたフレームかどうか Log.v("Jank detected!", frameData.toString()) } } } } 基本的な使用方法 - 初期化 18 JankStats.createAndTrackでJankStatsのインスタンスを生成
© ZOZO, Inc. class MainActivity : ComponentActivity() { private lateinit
var jankStats: JankStats override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { ... } jankStats = JankStats.createAndTrack(window) { frameData -> if (frameData.isJank) { // Jankと判定されたフレームかどうか Log.v("Jank detected!", frameData.toString()) } } } } 基本的な使用方法 - 初期化 JankStats.createAndTrackでJankStatsのインスタンスを生成 19 JankStatsのインスタンス生成時にdecorViewが生成されていない場合、 IllegalStateExceptionが発生するので注意
© ZOZO, Inc. 基本的な使用方法 - 初期化 20 class MainActivity
: ComponentActivity() { private lateinit var jankStats: JankStats override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { ... } jankStats = JankStats.createAndTrack(window) { frameData -> if (frameData.isJank) { // Jankと判定されたフレームかどうか Log.v("Jank detected!", frameData.toString()) } } } } JankStats.createAndTrackの第二引数には、フレーム情報を受け取るコールバック (JankStats.OnFrameListener)を渡す
© ZOZO, Inc. 21 isTrackingEnabledでフレーム情報収集の有効/無効を切り替える(デフォルト値はtrue) class MainActivity : ComponentActivity() {
... override fun onResume() { super.onResume() ... jankStats.isTrackingEnabled = true } override fun onPause() { super.onPause() jankStats.isTrackingEnabled = false } } 基本的な使用方法 - 初期化
© ZOZO, Inc. 基本的な使用方法 - FrameData 22 FrameData(フレームの情報)がLogcatに出力される
© ZOZO, Inc. 基本的な使用方法 - FrameData 23 • frameStartNanos ◦
フレームの開始時刻(ns) • frameDurationUiNanos ◦ フレームの長さ(ns) • isJank ◦ ジャンクかどうかを示すフラグ • states ◦ アプリの状態 (StateInfo) JankStats ライブラリ | App quality | Android Developers: https://developer.android.com/topic/performance/jankstats?hl=ja#reporting
© ZOZO, Inc. 基本的な使用方法 - FrameData 24 • frameStartNanos ◦
フレームの開始時刻(ns) • frameDurationUiNanos ◦ フレームの長さ(ns) • isJank ◦ ジャンクかどうかを示すフラグ • states ◦ アプリの状態 (StateInfo) JankStats ライブラリ | App quality | Android Developers: https://developer.android.com/topic/performance/jankstats?hl=ja#reporting
© ZOZO, Inc. 基本的な使用方法 - FrameData 25
© ZOZO, Inc. 基本的な使用方法 - FrameData 26 空だが...?
© ZOZO, Inc. @Composable fun rememberMetricsStateHolder(): PerformanceMetricsState.Holder { val view
= LocalView.current return remember(view) { PerformanceMetricsState.getHolderForHierarchy(view) } } 基本的な使用方法 - PerformanceMetricsState 27 PerformanceMetricsState.Holderを使用する
© ZOZO, Inc. 基本的な使用方法 - PerformanceMetricsState 28 @Composable fun JankyScreen()
{ val holder = rememberMetricsStateHolder() val key = "画面名" LaunchedEffect(holder) { // 状態を設定 holder.state?.putState(key, "JankyScreen") } JankyLazyColumn() // Jankが発生するComposable } PerformanceMetricsState#putStateにkey-value形式で状態をアプリの設定する
© ZOZO, Inc. 基本的な使用方法 - PerformanceMetricsState 29
© ZOZO, Inc. 基本的な使用方法 - PerformanceMetricsState 30 フレーム情報と アプリの状態が対応する🎉
© ZOZO, Inc. 基本的な使用方法 - PerformanceMetricsState 31 @Composable fun JankyScreen()
{ ... Column { Button(onClick = { // 無効になった状態を削除 holder.state?.removeState(key) }) { Text(text = "状態削除") } JankyLazyColumn() } }
© ZOZO, Inc. 基本的な使用方法 - PerformanceMetricsState 32 ボタンを押す前 ボタンを押した後 状態の削除も明示的に行う必要がある
© ZOZO, Inc. 基本的な使用方法 - nowinandroidの場合 33 nowinandroidではJankStatsを使用したJank検出用のComposableを作成し、 画面遷移時とスクロール時にputState/removeStateを実行している
© ZOZO, Inc. 基本的な使用方法 - nowinandroidの場合 34 nowinandroid | NiaAppState.kt:
https://github.com/android/nowinandroid/blob/main/app/src/main/java/com/google/samples/apps/nowinandroid/ui/NiaAppState.kt @Composable private fun NavigationTrackingSideEffect(navController: NavHostController) { TrackDisposableJank(navController) { metricsHolder -> val listener = NavController.OnDestinationChangedListener { _, destination, _ -> metricsHolder.state?.putState("Navigation", destination.route.toString()) } navController.addOnDestinationChangedListener(listener) onDispose { navController.removeOnDestinationChangedListener(listener) } } }
© ZOZO, Inc. 基本的な使用方法 - nowinandroidの場合 35 nowinandroid | JankStatsExtensions.kt:
https://github.com/android/nowinandroid/blob/4d65946f95f55505a21a1651c2fd5587cd5bb533/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/JankStatsExtensions.kt @Composable fun TrackScrollJank(scrollableState: ScrollableState, stateName: String) { TrackJank(scrollableState) { metricsHolder -> snapshotFlow { scrollableState.isScrollInProgress }.collect { isScrollInProgress -> metricsHolder.state?.apply { if (isScrollInProgress) { putState(stateName, "Scrolling=true") } else { removeState(stateName) } } } } }
© ZOZO, Inc. JankStats Libraryの使用方法まとめ 36 • フレーム情報の収集はコールバックを登録するだけなのでお手軽 • フレームの情報とアプリの状態を紐づけるには
PerformanceMetricsState#putStateを使用する • 無効になったアプリの状態はremoveStateで削除する • 状態管理にはDisposableEffectやLifecycleObserverを活用するのが良さそう ※ putSingleFrameStateという1フレーム分の状態を登録し、自動で削除するAPIもあります(使い所が難しい) ※
© ZOZO, Inc. 37 まとめと感想
© ZOZO, Inc. まとめと感想 38 • Jankとはフレームがスキップされ、アプリがスムーズでなくなることを指す • JankStats Libraryは本番環境で使用することで価値を発揮する
◦ ユーザーの手元で発生しているJankが検出可能になる ◦ Jankの分析に有用なデータを収集するためには、アプリのどのような情報をフ レームの情報に乗せるかが重要になりそう
None