https://developer.android.com/topic/libraries/app-startup?authuser=1
App Startup 라이브러리는 어플리케이션 시작 시 구성 요소를 초기화하는 간단하고 효율적인 방법을 제공한다.
라이브러리 및 앱 개발자 모두 App Startup 을 사용해서
startup 순서를 간소화하고 초기화 순서를 명시적으로 설정할 수 있다.
-1. ContentProvider initialization
예전에는 라이브러리가 어플리케이션의 Context 가 필요로 할 때, 아래와 같이 초기화 코드를 작성하곤했다.
class HelloApplication : Application() {
override fun onCreate() {
super.onCreate()
SomeLibrary.initialize(this)
}
}
앱 시작 시 WorkManager, Lifecycle 과 같은 컴포넌트는 ContentProvider 를 사용하여 각 dependency 를 초기화한다.
이 초기화 코드는 Application.onCreate() 가 호출되기 전! 앱이 Cold start 를 통과한 후 자동으로 초기화를 실행하고,
각 ContentProvider 의 onCreate() 가 호출되면서 모든 라이브러리가 초기화된다.
<manifest>
<application>
...
<provider
android:name="com.facebook.FacebookContentProvider"
android:authorities="com.facebook.FacebookContentProvider{appId}"
android:exported="true" />
...
</application>
</manifest>
0. Why use App Startup?
- ContentProvider 는 인스턴스화 비용이 든다.
- 각 컴포넌트 별 ContentProvider 를 갖게되어 수가 많아지면 각자 인스턴스화 되어 앱 시작 속도가 늦춰진다
- 단일 ContentProvider 를 공유하는 컴포넌트 Initializer 를 정의하면 시간을 단축시킬 수 있다
- 시작 순서를 늦출 수 있으며, 확정되지 않은 순서로 초기화한다.
- 안드로이드에는 초기화 순서에 대해 알 수 없어 다른 라이브러리에 종속되어 있을 때 문제가 발생할 수 있다.
App Startup 을 사용하게되면 각 컴포넌트 대해 별도의 ContentProvider 를 사용하지 않아도 되고
앱 시작 시 컴포넌트를 초기화 하는 성능과 방법을 제공해서 설치 비용을 줄일 수 있다.
또한 단일 ContentProvider 로 공유하는 컴포넌트 Initializer 를 정의하여 모든 종속성의 초기화를 실행한다.
1. Setup
dependencies {
implementation "androidx.startup:startup-runtime:1.0.0-alpha01"
}
2. Initialize components at app startup
앱 시작 시 App Startup 을 사용하여 컴포넌트를 자동으로 초기화하려면,
초기화해야하는 컴포넌트를 위한 Initializer 를 정의해야 한다.
Implement component initializers
Initializer<T> 인터페이스를 구현하는 클래스를 생성해서 각 컴포넌트 Initializer 를 정의한다.
이 인터페이스는 두 가지 중요한 메서드를 정의한다.
- create() : 컴포넌트를 초기화하는데 필요한 모든 동작을 포함하고 T 의 인스턴스를 리턴한다.
- dependencies()
- Initializer 가 의존하는 다른 Initializer<T> 객체의 목록을 리턴하도록 명시한다.
- 이 메서드로 시작 시 앱이 Initializer 를 실행하는 순서를 제어할 수 있다.
- ex1) 앱이 WorkManager 에 의존하고 시작 시 초기화 필요하다고 가정한다.
- Initializer<WorkManager> 를 구현하는 WorkManagerInitializer 클래스를 정의한다.
- WorkManager 는 다른 라이브러리에 의존하지 않기 때문에 dependencies() 메서드는 빈 리스트를 리턴한다.
// Initializes WorkManager.
class WorkManagerInitializer : Initializer<WorkManager> {
// context : application context
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<*>>> {
// No dependencies on other libraries.
return emptyList()
}
}
- ex2) 앱이 ExampleLogger 라는 라이브러리에 의존한다고 가정하고, 이 라이브러리는 WorkManager 에 의존한다고 가정해본다.
- 위 종속성은 App Startup 이 WorkManager 를 먼저 초기화해야 하는 것을 의미한다
- Initializer<ExampleLogger> 를 구현하는 ExampleLoggerInitializer 클래스를 정의한다.
- dependencies() 메서드에 WorkManagerInitializer 를 포함하기 때문에,
App Startup 은 ExampleLogger 전에 WorkManager 를 초기화한다.
// Initializes ExampleLogger.
class ExampleLoggerInitializer : Initializer<ExampleLogger> {
override fun create(context: Context): ExampleLogger {
// WorkManager.getInstance() is non-null only after
// WorkManager is initialized.
return ExampleLogger(WorkManager.getInstance(context))
}
override fun dependencies(): List<Class<out Initializer<*>>> {
// Defines a dependency on WorkManagerInitializer so it can be
// initialized after WorkManager is initialized.
return listOf(WorkManagerInitializer::class.java)
}
}
Note :
이전에 앱에서 컴포넌트 초기화를 위해 content provider 를 사용한 경우, App Startup 사용 시에는 제거해야 한다.
Set up manifest entries
App Startup 은 컴포넌트 Initializer 를 발견하기 위해 사용하는 InitializationProvider 라는 content provider 를 포함한다. 매니페스트에서 InitializationProvider 항목 안에 <meta-data> 항목을 먼저 확인해서 컴포넌트 Initializer 를 발견한 다음, 발견된 Initializer 의 dependencies() 메서드를 호출한다.
App Startup 에서 컴포넌트 Initializer 를 발견하려면 아래 조건 중 하나를 충족해야 한다.
- 컴포넌트 Initializer 는 InitializationProvider 매니페스트 항목 안에 <meta-data> 항목을 정의해야 한다
- 컴포넌트 Initializer 는 이미 발견 가능한 Initializer 의 dependencies() 메서드에 추가해야 한다
WorkManagerInitializer 와 ExampleLoggerInitializer 예제를 다시 보면, 매니페스트 파일에 아래와 같이 추가해야 한다.
ExampleLoggerInitializer 의 dependencies() 에 WorkManagerInitializer 가 추가되어있기 때문에
WorkManagerInitializer 의 <meta-data> 항목이 아닌 ExampleLoggerIniitalizer 로 정의하면 된다.
(tools:node="merge" 는 매니페스트 병합 툴이 충돌하는 항목을 해결하도록 하는 역할)
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<!-- This entry makes ExampleLoggerInitializer discoverable. -->
<meta-data android:name="com.example.ExampleLoggerInitializer"
android:value="androidx.startup" />
</provider>
Run lint checks
App Startup 라이브러리에는 컴포넌트 Initializer 를 올바르게 정의했는지 확인을 위한 lint 규칙 셋이 포함되어 있다.
커맨드 라인 ./gradlew :app:lintDebug 로 실행할 수 있다.
3. Manually initialize components
일반적으로 App Startup 을 사용할 때, InitializationProvider 객체는 AppInitializer 라는 엔터티를 사용하여 어플리케이션 시작 시 컴포넌트 Initializer 를 자동으로 발견하고 실행한다.
그러나 앱 시작 시 필요하지 않은 컴포넌트를 수동으로 초기화하기 위해 AppInitializer 를 직접 사용하기도 한다. lazy 초기화라고 하며 시작 비용을 최소화하는데 도움이 될 수 있다.
(수동으로 초기화하려면 모든 컴포넌트에 대해 자동 초기화를 비활성화해야 한다.)
Disable automatic initialization for an individual component
- 단일 컴포넌트의 자동 초기화를 비활성화하려면 매니페스트에서 해당 컴포넌트의 Initializer 의 <meta-data> 를 제거한다.
- 매니페스트가 병합된 후에도 해당 항목을 제거할 수 있도록 tools:node="remove" 를 사용한다!
- 자동 초기화 비활성화한 컴포넌트의 depedencies() 에 해당하는 항목도 같이 비활성화된다.
<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>
Disable automatic initialization for all components
모든 자동 초기화를 비활성화하려면, 매니페스트에서 InitializationProvider 항목 자체를 제거한다.
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />
Manually call component initializers
컴포넌트 자동 초기화를 비활성화할 경우, 아래 코드와 같이 AppInitializer 를 사용하여 해당 컴포넌트와 그 dependency 들을 수동으로 초기화할 수 있으며, WorkManager 도 같이 초기화된다.
AppInitializer.getInstance(context)
.initializeComponent(ExampleLoggerInitializer::class.java)
'Android개발' 카테고리의 다른 글
Migrating build.gradle from Groovy to Kotlin (0) | 2020.09.25 |
---|---|
Android Lint #2 - Custom Lint (0) | 2020.07.03 |
Android Lint #1 - 기본 (0) | 2020.07.02 |
App Startup time (1) | 2020.06.25 |
Elevation (0) | 2020.03.18 |
댓글