Androidアプリ起動時の初期化処理
これは株式会社TimeTree Advent Calendar 2024の19日目の記事です。
こんにちは。TimeTreeのAndroidエンジニアの笠松です。
この記事ではTimeTreeのAndroidアプリの初期化周りの処理をご紹介します。特に以下の内容を取り上げます。
- スプラッシュ画面起動前の初期化処理
- スプラッシュ画面起動開始時の初期化処理
- フォアグラウンド時、バックグランド時の処理登録
スプラッシュ画面起動前の初期化処理
TimeTreeでは、Androidの公式ライブラリであるApp Startupライブラリを採用しています。
本ライブラリはアプリ起動時のコンポーネント初期化をサポートします。本ライブラリは単一のコンテンツプロバイダを利用して初期化する仕組みを提供するため、コンテンツプロバイダに依存したコンポーネントの初期化を効率的に行うことができます。
使用方法は以下のコードのようにcreate
関数で初期化処理を実装し、dependencies
で初期化の順序を指定します。以下の例ではFirstInitializer
の初期化が完了したら、SecondInitializer
の初期化が起動します。
class SecondInitializer : Initializer<T> {
override fun create(context: Context): T {
//初期化処理
}
override fun dependencies(): List<Class<out Initializer<*>>> = listOf(
FirstInitializer::class.java
)
}
より詳細なマニフェストの設定等は公式ドキュメントをご参照ください。
例えば、Firebaseを初期化する場合、以下のようにFirebaseApp
とFirebaseCrashlytics
だけをこの段階で初期化します。クラッシュの早期検知を有効化し、それ以外の初期化処理は後回しにすることで、スプラッシュ画面の起動時間を短縮するためです。依存関係がないため、dependencies
は空リストを指定します。
class FirebaseCoreInitializer : Initializer<Boolean> {
override fun create(context: Context): Boolean {
FirebaseApp.initializeApp(context)
FirebaseCrashlytics.getInstance()
return true
}
override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
}
スプラッシュ画面起動開始時の初期化処理
スプラッシュ画面起動開始時の初期化処理を行うため、以下のようにInitializer
のcreate
関数でアプリケーションコールバックを登録し、onActivityCreated
のタイミングで初期化処理を呼び出します。
例えば、FirebaseAnalytics
などの初期化はこのタイミングで行います。dependencies
でFirebaseCoreInitializer
を指定し、FirebaseApp
の初期化完了後に処理を開始できるようにします。
class AppComponentsInitializer : Initializer<Boolean> {
...
@Inject
internal lateinit var delegate: ApplicationLifecycleCallbacks
override fun create(context: Context): Boolean {
val application = context.applicationContext as Application
application.registerActivityLifecycleCallbacks(object : DefaultActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
delegate.onAppFirstScreenLaunch(activity)
}
})
}
override fun dependencies(): List<Class<out Initializer<*>>> = listOf(
FirebaseCoreInitializer::class.java,
...
)
}
処理を拡張可能にする仕組みとして、以下のコードのようにApplicationLifecycleObserver
インターフェイスを定義しています。このインターフェイスを継承するクラスを作成し、Dagger HiltでSetに追加することで、スプラッシュ画面の初回起動時に実行する処理を簡単に追加できます。
interface ApplicationLifecycleObserver {
fun onAppFirstScreenLaunch(activity: Activity) {}
}
@Singleton
class ApplicationLifecycleCallbacks @Inject constructor(
private val observers: Provider<Set<@JvmSuppressWildcards ApplicationLifecycleObserver>>
) {
fun onAppFirstScreenLaunch(activity: Activity) {
observers.get().forEach { it.onAppFirstScreenLaunch(activity) }
}
}
フォアグラウンド・バックグラウンド時の処理登録
フォアグラウンド・バックグラウンド時の処理登録を行うため、以下のようにProcessLifecycleOwner
にオブザーバーを登録します。ProcessLifecycleOwner
を使用するためにdependencies
にProcessLifecycleInitializer
を指定します。
class AppComponentsInitializer : Initializer<Boolean> {
...
@Inject
internal lateinit var observer: ProcessLifecycleObservers
override fun create(context: Context): Boolean {
ProcessLifecycleOwner.get().lifecycle.addObserver(observer)
...
}
override fun dependencies(): List<Class<out Initializer<*>>> = listOf(
ProcessLifecycleInitializer::class.java,
...
)
}
フォアグラウンド・バックグラウンド遷移時の処理も、ProcessLifecycleObserver
インターフェイスを利用して追加可能です。このインターフェイスを継承するクラスを作成し、Dagger HiltでSetに作成したクラスを追加することで、各契機で実行する処理を簡単に追加できます。
interface ProcessLifecycleObserver {
fun onAppToForeground(lifecycleOwner: LifecycleOwner) {}
fun onAppToBackground(lifecycleOwner: LifecycleOwner) {}
}
@Singleton
class ProcessLifecycleObservers @Inject constructor(
private val observers: Provider<Set<@JvmSuppressWildcards ProcessLifecycleObserver>>
) : DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
observers.get().forEach { it.onAppToForeground(owner) }
}
override fun onStop(owner: LifecycleOwner) {
observers.get().forEach { it.onAppToBackground(owner) }
}
}
まとめ
スプラッシュ画面起動前の初期化処理、スプラッシュ画面起動開始時の初期化処理、フォアグラウンド時、バックグランド時の処理登録の実装方法をご紹介しました。
ご紹介した仕組みは各社でそれぞれあると思いますが、ご参考になれば幸いです。
TimeTreeのエンジニアによる記事です。メンバーのインタビューはこちらで発信中! note.com/timetree_inc/m/m4735531db852
Discussion