Primary/Android

App Startup

해스끼 2023. 1. 25. 17:18

몇몇 클래스는 사용하기 전에 초기화해야 하는 경우가 있다. 예를 들어 로그 라이브러리인 Timber는 앱을 시작한 후 최대한 빨리 초기화해야 한다. ``Application`` 클래스 안에서 초기화할 수도 있지만, startup 라이브러리를 사용하면 앱이 시작될 때 자동으로 초기화할 수 있다.

설치

``build.gradle`` 파일에 다음 의존성을 추가하자.

dependencies {
    implementation("androidx.startup:startup-runtime:1.1.1")
}

Startup 라이브러리의 장점

이전에는 클래스를 ``ContentProvider``에서 초기화하는 경우도 있었지만, ``ContentProvider`` 자체가 만들기 비싼 데다가 결정적으로 클래스의 초기화 순서를 지정할 수 없다는 문제가 있다. 어떤 클래스를 초기화할 때 Timber를 사용하고 싶다면, Timber가 이미 초기화됐어야 한다. 하지만 ``ContentProvider``는 초기화 순서를 보장하지 않기 때문에 곤란하다.

 

Startup 라이브러리를 사용하면 위의 문제를 해결할 수 있다. Startup의 ``Initializer<T>``는 ``ContentProvider``보다 가볍고 빠르며, 초기화 순서를 지정할 수도 있다. 어디 한번 사용해 보자.

Initializer 구현

``Initializer<T>`` 인터페이스를 implement하여 초기화 작업을 구현하자. ``Initializer<T>``에는 다음의 두 함수가 선언되어 있다.

  • ``create()``: 클래스를 초기화하고 ``T`` 타입 객체를 반환한다. ``T``는 초기화할 클래스이다. 초기화한 클래스의 인스턴스를 반환하기 어렵다면 ``Unit``으로 지정해도 된다.
  • ``dependencies()``: 이 initializer에 의존하는 하위 ``Initializer<T>`` 클래스의 리스트를 반환한다. 여기에서 초기화 순서를 지정할 수 있다.

예를 들어 Android ``WorkManager``를 초기화하는 코드는 다음과 같다.

class WorkManagerInitializer : Initializer<WorkManager> {
    override fun create(context: Context): WorkManager {
        val configuration = Configuration.Builder().build()
        WorkManager.initialize(context, configuration)
        return WorkManager.getInstance(context)
    }
    override fun dependencies(): List<Class<out Initializer<*>>> {
        // 부모 initializer 없음
        return emptyList()
    }
}

이제 ``WorkManagerInitializer``에 의존하는 ``ExampleLoggerInitializer``를 선언해 보자.

class ExampleLoggerInitializer : Initializer<ExampleLogger> {
    override fun create(context: Context): ExampleLogger {
        // WorkManager는 이미 초기화되어 있음
        return ExampleLogger(WorkManager.getInstance(context))
    }

    override fun dependencies(): List<Class<out Initializer<*>>> {
        // 부모 initializer
        return listOf(WorkManagerInitializer::class.java)
    }
}

``dependencies()`` 함수에서 ``WorkManagerInitializer``를 부모 initializer로 지정했다. 따라서 ``ExampleLogger``는 ``WorkManager``가 초기화된 후에 초기화된다.

Manifest 정의

Android가 initializer를 인식하고 실행하게 하려면, 구현한 initializer를 manifest에 등록해야 한다. Startup 라이브러리에는 ``InitializationProvider``라는 특별한 content provider가 있다. 이 안에 모든 initializer를 ````로 선언하면 된다. 

 

위에서 구현한 두 initializer를 등록하는 구문은 다음과 같다.

<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    android:exported="false"
    tools:node="merge">
    <meta-data  android:name="com.example.WorkManagerInitializer"
          android:value="androidx.startup" />
    <meta-data  android:name="com.example.ExampleLoggerInitializer"
          android:value="androidx.startup" />
</provider>

Startup 라이브러리는 ``<meta-data>``로 선언된 initializer를 먼저 인식하고, 인식된 initializer의 ``dependencies()``에 선언된 initializer 역시 인식한다. 따라서 위의 경우에는 ``ExampleLoggerInitializer``만 ``<meta-data>``로 등록하면 ``WorkManagerInitializer``까지 인식된다.

<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    android:exported="false"
    tools:node="merge">
    <!-- 이거만 적어도 된다. -->
    <meta-data  android:name="com.example.ExampleLoggerInitializer"
          android:value="androidx.startup" />
</provider>

이제 ``InitializationProvider``에서 ``AppInitializer`` 클래스를 사용하여 initializer를 인식하고 실행할 수 있다.

수동으로 초기화하고 싶다면?

앱이 시작될 때가 아닌, 클래스가 처음으로 사용될 때 초기화하고 싶을 수도 있다. 이처럼 ``AppInitializer``에 직접 접근하여 원하는 시점에 클래스를 초기화할 수 있다.

자동 초기화 비활성화

우선 자동 초기화를 비활성화하기 위해 manifest에서 initializer를 제거하자. 이렇게 하면 제거된 initializer의 부모까지 모두 제거된다.

<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    android:exported="false"
    tools:node="merge">
    <meta-data android:name="com.example.ExampleLoggerInitializer"
              tools:node="remove" />
</provider>

모든 자동 초기화 클래스 비활성화

모든 initializer를 한 번에 비활성화하고 싶다면, ``InitializationProvider`` 자체를 제거하면 된다.

<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    tools:node="remove" />

수동 초기화

이제 원하는 시점에 ``AppInitializer``를 사용하여 클래스를 초기화할 수 있다.

AppInitializer.getInstance(context)
    .initializeComponent(ExampleLoggerInitializer::class.java)

이 코드는 ``WorkManagerInitializer``를 먼저 실행한 후 ``ExampleLoggerInitializer``를 실행한다.

더 보기

 

App Startup  |  Android Developers

Stay organized with collections Save and categorize content based on your preferences. The App Startup library provides a straightforward, performant way to initialize components at application startup. Both library developers and app developers can use Ap

developer.android.com