본문 바로가기
Android개발

App Startup

by 궝테스트 2020. 6. 25.

https://developer.android.com/topic/libraries/app-startup?authuser=1

 

App Startup  |  Android 개발자  |  Android Developers

The App Startup library provides a straightforward, performant way to initialize components at application startup. Both library developers and app developers can use App Startup to streamline startup sequences and explicitly set the order of initializatio

developer.android.com

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

댓글