起動処理とBaseline Profiles
コールドスタートを高速化します。
「起動処理とBaseline Profiles」はCoddyKit上の無料Android Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAndroid Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Android Academyコースには全4レッスンが含まれています。
第一印象:アプリの起動
起動時間は、すべてのユーザーが最初に体験するものです。Google Playでも、起動が遅いことは品質上の問題として扱われます。コールドスタートが速いアプリは高品質に感じられますが、遅いアプリはユーザーに離脱されやすくなります。
このレッスンでは、3種類の起動、起動を遅くする原因、そしてコールドスタートを大幅に高速化する最新のツールであるApp StartupとBaseline Profilesについて学びます。
コールド、ウォーム、ホットスタート
Androidでは、起動シナリオを遅いものから速いものへ、次の3種類に定義しています。
- コールドスタート:プロセスが存在しません。Androidがプロセスを作成し、
Applicationを実行してから、最初の画面を表示します。最も遅く、最も重点的に最適化すべき起動です。 - ウォームスタート:プロセスは起動していますが、Activityを再作成する必要があります。
- ホットスタート:Activityがまだメモリ上にあり、前面に戻すだけです。ほぼ瞬時に完了します。
最適化ではコールドスタートに重点を置きます。新規ユーザーや再訪ユーザーが最も頻繁に体験する起動だからです。
起動時間を測定する
測定しなければ、改善することはできません。簡単な方法は2つあります。
- Logcat:システムが、最初のフレームが表示されるまでの時間を示す
Displayed行を記録します。 - Macrobenchmark:
StartupTimingMetricで、安定して再現可能なコールドスタートの数値を取得できます。
以下のadbコマンドを実行し、Displayed行を確認してください。
# Cold-start the app and log time to first frame
adb shell am start -W -S com.example.app/.MainActivity
# Output includes:
# TotalTime: 412 <- ms to first frame
# Or filter logcat:
adb logcat | grep "Displayed com.example.app"Application.onCreateを軽く保つ
Application.onCreate()内の処理はすべて、最初のフレームが表示される前にメインスレッドで実行されます。ここで重い初期化を行うと、起動が直接遅延します。
以下の悪い例では、複数のライブラリを即座に初期化しています。最初の画面に必要ない処理は、遅延させるかバックグラウンドで実行してください。
// SLOW: blocks the first frame with eager init
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
Analytics.init(this) // network, disk
ImageLoader.preload(this) // heavy
Database.warmUp(this) // disk I/O
}
}
// Each of these adds milliseconds before the user sees anything.Jetpack App Startupライブラリ
App Startupライブラリは、時間のかかる複数のライブラリ用Content Providerを、単一の共有Content Providerに置き換えます。また、初期化の順序と依存関係を明確に表現できます。
コンポーネントごとにInitializerを実装すると、App Startupが依存関係の順序に従って一度だけ実行します。
class AnalyticsInitializer : Initializer<Analytics> {
override fun create(context: Context): Analytics {
return Analytics.init(context.applicationContext)
}
// Runs after Logger is ready
override fun dependencies() = listOf(LoggerInitializer::class.java)
}
// Registered via a single merged provider in the manifest,
// avoiding one ContentProvider per library.遅延初期化とバックグラウンド初期化
起動時に実行する処理の順序を整えるよりも、起動時に行う処理自体を減らすほうが効果的です。方法は2つあります。
- 遅延初期化:Kotlinの
by lazyを使い、初めて使用するときに重いオブジェクトを生成します。 - バックグラウンド実行:UIに関係しない初期化をメインスレッドから移します。
これで、ユーザーがまだ必要としていない処理によって最初のフレームがブロックされなくなります。
class MyApp : Application() {
// Built only when first accessed, not during onCreate
val imageLoader by lazy { ImageLoader.build(this) }
override fun onCreate() {
super.onCreate()
// Push non-critical setup off the main thread
CoroutineScope(Dispatchers.Default).launch {
Analytics.init(applicationContext)
}
}
}AOTとJIT:初回実行が遅い理由
デフォルトでは、Androidは解釈実行とJust-In-Time(JIT)コンパイルを組み合わせて、アプリのバイトコードを実行します。頻繁に実行されるコードも、最初は解釈実行されるため遅く、後になってからランタイムがnativeコードへコンパイルします。
これが、コールドスタートや最初のスクロールが遅く感じられる理由です。Baseline Profilesは、インストール時に重要なコードをAhead-Of-Time(AOT)コンパイルするようデバイスに指示することで、この問題を解決します。
Baseline Profileとは
Baseline Profileは、重要な操作(起動や最初のスクロールなど)の実行中に使用されるクラスとメソッドの一覧です。これをアプリに含めて配布すると、インストール時にデバイスが対象メソッドをAOTコンパイルするため、初回起動からnativeコードと同等の速度で実行されます。
Googleによると、機能コードを変更しなくても、プロファイルだけで起動時間が20~40%改善することがよくあります。
// build.gradle.kts
plugins { id("androidx.baselineprofile") }
dependencies {
baselineProfile(project(":baselineprofile"))
}
// The generated profile ships as
// assets/dexopt/baseline.prof
// and is applied automatically at install.Baseline Profileを生成する
デバイス上で重要な操作を実行する小さなテストを作成すると、プロファイルを生成できます。ツールが実行されたメソッドを記録し、プロファイルファイルを書き出します。その後、ファイルをコミットして再ビルドします。
以下は、起動とスクロールを記録する一般的な生成処理です。
@RunWith(AndroidJUnit4::class)
class BaselineProfileGenerator {
@get:Rule val rule = BaselineProfileRule()
@Test
fun generate() = rule.collect(packageName = "com.example.app") {
pressHome()
startActivityAndWait()
// exercise the critical journey
device.findObject(By.res("feed")).fling(Direction.DOWN)
}
}
// Run the generateBaselineProfile Gradle task to produce the file.効果を検証する
プロファイルを適用した場合と適用しない場合(CompilationMode.Noneと、プロファイルを使用するPartial)で起動時間を比較し、ベンチマークで改善を必ず確認してください。
測定しなければ、プロファイルによって改善したことを証明できません。また、古くなったプロファイルは逆効果になる場合もあります。ホットパスが大きく変わるたびに再生成してください。
@Test
fun startupWithProfile() = rule.measureRepeated(
packageName = "com.example.app",
metrics = listOf(StartupTimingMetric()),
iterations = 10,
startupMode = StartupMode.COLD,
compilationMode = CompilationMode.Partial() // uses the baseline profile
) {
pressHome()
startActivityAndWait()
}起動最適化の計画
次のように、繰り返し実行できる計画にまとめます。
- Macrobenchmarkと
adb am start -Wでコールドスタートを測定する。 Application.onCreateを削減する。by lazyで遅延させ、処理をメインスレッドから移す。- App Startupを使ってContent Providerを統合し、初期化の順序を設定する。
- 重要な処理経路をAOTコンパイルするためのBaseline Profileをアプリに含める。
- ベンチマークで効果を検証し、プロファイルを最新に保つ。
その結果、ユーザーが体感できる、軽快な最初のフレームを実現できます。
クイックチェック
アプリにBaseline Profileを含めて配布します。起動を改善するために、主にどのような処理を行いますか?
まとめ:最初のフレームから高速に
最も目につきやすいパフォーマンス指標である起動を最適化する方法を学びました。
- コールドスタートを最適化し、Macrobenchmarkと
adb am start -Wで測定する。 Application.onCreateを軽く保つ。遅延初期化と、UIに関係しない処理のバックグラウンド実行を行う。- App Startupライブラリを使ってProviderを統合し、Initializerの順序を設定する。
- Baseline Profileを含めて配布し、インストール時にホットコードをAOTコンパイルして、初回実行からnativeコードと同等の速度で実行できるようにする。
- ベンチマークで効果を必ず検証し、プロファイルを最新に保つ。
これで、Performance Optimization & Profilingは完了です。測定、再コンポジションの抑制、リークの修正、そして高速な起動ができるようになりました。
よくある質問
「起動処理とBaseline Profiles」レッスンは無料ですか?
はい。「起動処理とBaseline Profiles」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Android Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Android Academyコースには全4レッスンが含まれています。
「起動処理とBaseline Profiles」で何を学びますか?
コールドスタートを高速化します。 ブラウザで直接実行するハンズオンコードでAndroid Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Android Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのAndroid Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「起動処理とBaseline Profiles」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このAndroid Academyレッスンでコードを書いて実行できますか?
はい。すべてのAndroid Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- パフォーマンスを測定する
- 再コンポジションを制御する
- メモリリークと修正方法
- 起動処理とBaseline Profiles