0Pricing
Android Academy · レッスン

起動処理と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フィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. パフォーマンスを測定する
  2. 再コンポジションを制御する
  3. メモリリークと修正方法
  4. 起動処理とBaseline Profiles
← Android Academyに戻る