パフォーマンスに関する背景についてご説明します。
パフォーマンス スポットライト ウィークの 3 日目へようこそ。本日は、アプリのパフォーマンスの重要な領域に関する詳細とガイダンスについて、引き続きご紹介します。プロファイルに基づく最適化、Jetpack Compose のパフォーマンスの改善、舞台裏での作業に関する考慮事項について説明します。では、詳しく見ていきましょう。
プロファイル ガイド付き最適化
ベースライン プロファイルと起動プロファイルは、Android アプリの起動とランタイムのパフォーマンスを改善するための基盤となります。これらは、プロファイルに基づく最適化と呼ばれるパフォーマンス最適化のグループの一部です。
アプリがパッケージ化されると、d8 dexer がクラスとメソッドを取得し、アプリの classes.dex ファイルにデータを入力します。ユーザーがアプリを開くと、これらの dex ファイルが読み込まれ、アプリが起動するまで順番に処理されます。スタートアップ プロファイルを指定すると、最初の classes.dex ファイルにどのクラスとメソッドをパックするかを d8 に伝えることができます。この構造により、アプリが読み込むファイルの数が減り、起動速度が向上します。
ベースライン プロファイルを使用すると、ジャストインタイム(JIT)コンパイルの手順をユーザー デバイスからデベロッパー マシンに効果的に移行できます。生成された Ahead Of Time(AOT)コンパイル済みコードは、起動時間とレンダリングの問題の両方を軽減することが証明されています。
Trello とベースライン プロファイル
Trello アプリのエンジニアに、ベースライン プロファイルがアプリのパフォーマンスにどのような影響を与えたかについて尋ねました。メインのユーザー ジャーニーにベースライン プロファイルを適用した後、Trello はアプリの起動時間を 25 % 大幅に短縮しました。
Trello は、ベースライン プロファイルを使用してアプリの起動時間を 25 % 短縮できました。
Meta のベースライン プロファイル
また、Meta のエンジニアが、ベースライン プロファイルを使用して Android アプリを高速化する方法に関する記事を最近公開しました。
Meta のアプリ全体で、ベースライン プロファイルを適用した後に、さまざまな重要な指標が最大 40 % 改善されたことが確認されています。
このような技術的な改善は、ユーザー満足度とビジネスの成功の向上にもつながります。この情報をプロダクト オーナー、CTO、意思決定者と共有することで、アプリのパフォーマンスを向上させることもできます。
ベースライン プロファイルを使ってみる
ベースライン プロファイルまたはスタートアップ プロファイルを生成するには、アプリをテストする Macrobenchmark テストを記述します。テスト中に、アプリのコンパイルで使用されるプロファイル データが収集されます。テストは新しい UiAutomator API を使用して記述されています。これについては明日説明します。
このようなベンチマークの作成は簡単です。完全なサンプルは GitHub で確認できます。
@Test
fun profileGenerator() {
rule.collect(
packageName = TARGET_PACKAGE,
maxIterations = 15,
stableIterations = 3,
includeInStartupProfile = true
) {
uiAutomator {
startApp(TARGET_PACKAGE)
}
}
}考慮事項
まず、ユーザーが最もよく利用するパスのベースライン プロファイルとスタートアップ プロファイルをマクロベンチマーク テストで記述します。これは、ユーザーがアプリにアクセスするメインのエントリ ポイントを意味します。通常は、ログイン後です。その後、ベースライン プロファイルのみの全体像を把握するために、テストケースの作成を続けます。ベースライン プロファイルですべてをカバーする必要はありません。最も使用されるパスに沿って、フィールドでのパフォーマンスを測定します。詳しくは明日の投稿で説明します。
プロファイルに基づく最適化を始める
ベースライン プロファイルの仕組みについて詳しくは、Android Developers Summit のこちらの動画をご覧ください。
また、Android ビルド時間の Profile Guided Optimization のエピソードで、さらに詳しくご覧ください。
また、ベースライン プロファイルと起動プロファイルに関する詳細なガイダンスも用意されています。
Jetpack Compose のパフォーマンスの改善
Android の UI フレームワークでは、エンジニアリング チームのパフォーマンスへの投資が実を結びました。Jetpack Compose のバージョン 1.9 では、内部の長時間のスクロール ベンチマーク テストでスクロール ジャンクが 0.2 % にまで低下しました。
これらの改善は、最新リリースに搭載されたいくつかの機能によって実現しました。
カスタマイズ可能なキャッシュ ウィンドウ
デフォルトでは、遅延レイアウトはスクロール方向に 1 つのアイテムのみを事前にコンポーズし、スクロールして画面外に移動したものは破棄されます。ビューポートの割合または dp サイズで、保持するアイテムの数をカスタマイズできるようになりました。これにより、アプリはより多くの作業を事前に行い、フレーム間の一時停止可能なコンポーザブルを有効にした後、利用可能な時間をより効率的に使用できます。
カスタマイズ可能なキャッシュ ウィンドウの使用を開始するには、LazyLayoutCacheWindow をインスタンス化して、遅延リストまたは遅延グリッドに渡します。さまざまなキャッシュ ウィンドウ サイズ(ビューポートの 50% など)を使用して、アプリのパフォーマンスを測定します。最適な値は、コンテンツの構造とアイテムのサイズによって異なります。
val dpCacheWindow = LazyLayoutCacheWindow(ahead = 150.dp, behind = 100.dp)
val state = rememberLazyListState(cacheWindow = dpCacheWindow)
LazyColumn(state = state) {
// column contents
}一時停止可能なコンポジション
この機能を使用すると、コンポジションを一時停止して、作業を複数のフレームに分割できます。この API は 1.9 で導入され、1.10 では遅延レイアウトのプリフェッチでデフォルトで使用されるようになりました。複雑なアイテムで、合成時間が長いほど、メリットが大きくなります。
Compose のパフォーマンス最適化
Compose のバージョン 1.9 と 1.10 では、チームはあまり目立たない最適化もいくつか行っています。
内部でコルーチンを使用するいくつかの API が改善されました。たとえば、Draggable と Clickable を使用すると、デベロッパーは反応時間の短縮と割り当て数の増加を確認できます。
レイアウトの長方形のトラッキングを最適化し、onVisibilityChanged() や onLayoutRectChanged() などの修飾子のパフォーマンスを改善しました。これにより、これらの API を明示的に使用していない場合でも、レイアウト フェーズが高速化されます。
パフォーマンスのもう 1 つの改善点は、onPlaced() を介して位置を観察するときにキャッシュに保存された値を使用することです。
バックグラウンドでテキストをプリフェッチする
バージョン 1.9 以降では、Compose でバックグラウンド スレッドでテキストをプリフェッチできるようになりました。これにより、キャッシュを事前に準備してテキスト レイアウトを高速化できます。これはアプリのレンダリング パフォーマンスに関連します。レイアウト中、テキストは Android フレームワークに渡され、そこで単語キャッシュが入力されます。デフォルトでは、これは UI スレッドで実行されます。プリフェッチと単語キャッシュのバックグラウンド スレッドへの入力処理をオフロードすると、特に長いテキストのレイアウトを高速化できます。バックグラウンド スレッドでプリフェッチするには、次のように LocalBackgroundTextMeasurementExecutor を CompositionLocalProvider に渡すことで、内部で BasicText を使用している任意のコンポーザブルにカスタム エグゼキュータを渡すことができます。
val defaultTextMeasurementExecutor = Executors.newSingleThreadExecutor()
CompositionLocalProvider(
LocalBackgroundTextMeasurementExecutor provides DefaultTextMeasurementExecutor
) {
BasicText("Some text that should be measured on a background thread!")
}テキストによっては、テキスト レンダリングのパフォーマンスが向上します。アプリのレンダリング パフォーマンスが向上していることを確認するには、ベンチマークを行い、結果を比較します。
バックグラウンド処理のパフォーマンスに関する考慮事項
バックグラウンド作業は、多くのアプリにとって不可欠な要素です。WorkManager や JobScheduler などのライブラリを使用して、次のようなタスクを実行している場合があります。
- 分析イベントを定期的にアップロードする
- バックエンド サービスとデータベース間のデータの同期
- メディアの処理(画像のサイズ変更や圧縮など)
これらのタスクを実行する際の主な課題は、パフォーマンスと電力効率のバランスをとることです。WorkManager を使用すると、このバランスを実現できます。この API は、電力効率を重視して設計されており、指定した制約やシステムによって課せられた制約など、さまざまな要因によって影響を受ける最適な実行ウィンドウに作業を延期できます。
ただし、WorkManager は万能なソリューションではありません。Android には、特定の一般的なコア ユーザー ジャーニー(CUJ)を念頭に置いて特別に設計された、電力最適化された API も多数あります。
バックグラウンド処理のランディング ページで、ウィジェットの更新やバックグラウンドでの位置情報の取得など、これらの処理の例をご確認ください。
バックグラウンド作業のローカル デバッグツール: 一般的なシナリオ
バックグラウンド作業をデバッグし、タスクが遅延または失敗した理由を把握するには、システムがタスクをどのようにスケジュールしたかを把握する必要があります。
このために、WorkManager には ローカルでデバッグしてパフォーマンスを最適化するのに役立つ関連ツールがいくつか用意されています(これらのツールの一部は JobScheduler でも使用できます)。WorkManager の使用時に発生する可能性のある一般的なシナリオと、それらのデバッグに使用できるツールについて説明します。
スケジュールされた作業が実行されない理由をデバッグする
スケジュール設定された作業が遅延したり、まったく実行されなかったりする原因は、指定された制約が満たされていない、または制約がシステムによって課せられているなど、さまざまな要因が考えられます。
スケジュール設定された作業が実行されない理由を調査する最初の手順は、作業が正常にスケジュール設定されたことを確認することです。 スケジュール設定のステータスを確認したら、作業の実行を妨げる制約や前提条件が満たされていないかどうかを判断します。
このシナリオをデバッグするためのツールはいくつかあります。
Background Task Inspector
Background Task Inspector は、Android Studio に直接統合されている強力なツールです。すべての WorkManager タスクとそれに関連付けられた状態(実行中、キューに登録済み、失敗、成功)を視覚的に表現します。
Background Task Inspector を使用して、スケジュールされた作業が実行されない理由をデバッグするには、リストに表示された Work のステータスを確認します。「キューに登録済み」ステータスは、Work がスケジュールされているものの、まだ実行を待機していることを示します。
メリット: このツールは、すべてのタスクを簡単に確認できるだけでなく、連鎖的な作業がある場合に特に便利です。Background Task Inspector には、前のタスクの失敗が次のタスクの実行に影響したかどうかを視覚化できるグラフビューが用意されています。
Background Task Inspector のリストビュー
Background Task Inspector のグラフビュー
adb shell dumpsys jobscheduler
このコマンドは、指定された制約とシステムによって課せられた制約とともに、すべてのアクティブな JobScheduler ジョブ(WorkManager Worker を含む)のリストを返します。また、ジョブ履歴も返します。
スケジュールされた作業と関連する制約を別の方法で表示する場合は、これを使用します。WorkManager 2.10.0 より前のバージョンの WorkManager では、adb shell dumpsys jobscheduler はこの名前の Worker のリストを返します。
[package name]/androidx.work.impl.background.systemjob.SystemJobService
アプリに複数のワーカーがある場合、WorkManager 2.10.0 に更新すると、ワーカー名が表示され、ワーカーを簡単に区別できるようになります。
#WorkerName#@[package name]/androidx.work.impl.background.systemjob.SystemJobService
メリット: このコマンドは、バックグラウンド タスク インスペクタでは判断できないシステムによる制約 があったかどうかを把握するのに役立ちます。たとえば、これによりアプリのスタンバイ バケットが返されます。これは、スケジュール設定された作業が完了するウィンドウに影響する可能性があります。
デバッグ ロギングを有効にする
カスタム ロギングを有効にすると、詳細な WorkManager ログが表示され、WM— が付加されます。
メリット: これにより、作業のスケジュール設定、制約の充足、ライフサイクル イベントのタイミングを把握できます。アプリの開発中にこれらのログを参照できます。
WorkInfo.StopReason
特定のワーカーで予測不可能なパフォーマンスが発生した場合は、WorkInfo.getStopReason を使用して、前回の実行試行でワーカーが停止した理由をプログラムで確認できます。
getWorkInfoByIdFlow を使用して WorkInfo を監視するようにアプリを構成し、バックグラウンド制限、制約、頻繁なタイムアウト、ユーザーによる停止などによって作業が影響を受けているかどうかを特定することをおすすめします。
メリット: WorkInfo.StopReason を使用して、ワーカーのパフォーマンスに関するフィールド データを収集できます。
Android Vitals でフラグが設定された WorkManager 属性の長い wake lock 時間をデバッグする
Android Vitals には、バッテリーの消耗の原因となっている wake lock をハイライト表示する「過度の部分的な wake lock」という指標があります。WorkManager はタスクを実行するためにウェイクロックを取得します。ウェイクロックが Google Play で設定されたしきい値を超えると、アプリの可視性に影響する可能性があります。ワークに起因する wake lock の時間が長すぎる理由をデバッグするにはどうすればよいですか?次のツールを使用できます。
Android Vitals のダッシュボード
まず、Android Vitals の過剰な wake lock のダッシュボードで、wake lock の時間が長い原因が WorkManager であり、アラームやその他の wake lock ではないことを確認します。他の API で作成されたウェイクロックを特定するのドキュメントを参照して、WorkManager によって保持されているウェイクロックを特定できます。
Perfetto
Perfetto は、システム トレースを分析するためのツールです。WorkManager のデバッグに特化した使用方法としては、[デバイスの状態] セクションで、作業の開始時刻、実行時間、消費電力への影響を確認できます。
[Device State: Jobs] トラックには、実行されたワーカーと関連するウェイクロックが表示されます。
Perfetto の [Device State] セクション。CleanupWorker と BlurWorker の実行が表示されています。
リソース
発生する可能性のある他のシナリオで使用できるデバッグ方法の概要については、WorkManager のデバッグページをご覧ください。
これらのメソッドを実際に試して、WorkManager のデバッグについて詳しく学ぶには、 高度な WorkManager とテストの Codelab をご覧ください。
次のステップ
本日は、コード圧縮を超えて、Android ランタイムと Jetpack Compose がアプリを実際にレンダリングする方法について説明しました。ベースライン プロファイルによるクリティカル パスの事前コンパイルや、新しい Compose 1.9 と 1.10 の機能によるスクロール状態の平滑化など、これらのツールはアプリの操作感に重点を置いています。また、バックグラウンド処理のデバッグに関するベスト プラクティスについても詳しく説明しました。
Android に質問する
金曜日に、パフォーマンスに関するライブ AMA を開催します。「#AskAndroid」を付けて質問をお寄せください。専門家が回答いたします。
課題
月曜日に R8 を有効にするようお願いしました。本日より、アプリのベースライン プロファイルを 1 つ生成していただくようお願い申し上げます。
Android Studio Otter では、ベースライン プロファイル ジェネレータ モジュール ウィザードにより、この作業がこれまで以上に簡単になります。最も重要なユーザー ジャーニー(アプリの起動とログインだけでも可)を選択し、プロファイルを生成します。
入手したら、Macrobenchmark を実行して CompilationMode.None と CompilationMode.Partial を比較します。
#optimizationEnabled を使用して、起動時間の改善をソーシャル メディアで共有しましょう。
明日の配信をお見逃しなく
R8 でアプリを圧縮し、プロファイルに基づく最適化でランタイムを最適化しました。しかし、これらの成果をステークホルダーにどのように証明すればよいでしょうか。また、回帰が本番環境に影響する前に検出するにはどうすればよいですか?
明日は Day 4: The Performance Leveling Guide を開催します。ここでは、Google Play Vitals のフィールド データから Perfetto を使用した詳細なローカル トレースまで、成功を測定する方法を詳しく説明します。
続きを読む
-
ハウツー
新機能の開発では、アプリのパフォーマンスが後回しにされることがよくあります。ただし、デベロッパーは常にパフォーマンスを意識しているわけではありませんが、ユーザーはアプリのパフォーマンスが遅れている箇所を正確に把握できます。
-
ハウツー
アプリのパフォーマンスは、スムーズな UI や起動時間の短さで語られることが多いですが、メモリはこれらの目に見える指標の基盤となるものです。デバイスのメモリがこれまで以上に重要になっていることは、周知の事実です。
-
ハウツー
本日、Google が発行する新しい確認済みのメールアドレスの認証情報を発表いたします。デベロッパーは、Android の認証情報マネージャー Digital Credential API から直接取得できるようになりました。
Niharika Arora, Jean-Pierre Pralle • 所要時間 3 分
最新情報の入手
Android 開発に関する最新の分析情報を毎週メールでお届けします。