1. 서론
최근 근무하며 진행중인 프로젝트에서 Timber 세팅과 일부 SDK 설정을 해야했다.
현재 프로젝트에서 Application
의 onCreate()
에는 다른 설정이 존재하여 Timber 및 SDK 초기화 설정을 추가하면 Apllication.onCreate()
가 복잡도가 증가하는 상황이었다.
따라서 Timber 및 SDK 설정을 마치 Spring 의 @Configuration
를 참고하여 분리된 설정을 만들고자 생각했다.
이미 과거에 Jetpack Startup 을 도입했던 경험이 있기 때문에 단순하게 도입을 하면 되는 상황이었지만 문서화를 하는 과정에서 보다 명확한 설명을 위해 알아본 내용을 정리해보고자 한다.
개인이나 지인 단위 프로젝트라면 그냥 적용하고 끝났겠지만...
새로 도입하는 내용이기 때문에 적용 배경과 도입 의도를 명확하게 기록하지 않으면, 불필요한 커뮤니케이션이 필요할 것이라 생각했다.
2. 왜 Jetpack Startup 을 써야하는가?
2.1. Jetpack Startup 공식 문서 살펴보기
공식문서 첫 문단을 보면 다음과 같은 내용을 확인할 수 있다.
앱 시작 라이브러리를 사용하면 애플리케이션 시작 시 구성요소를 간단하고 효율적으로 초기화할 수 있습니다.
라이브러리 개발자는 물론 앱 개발자도 앱 시작을 사용하여 시작 시퀀스를 간소화하고 초기화 순서를 명시적으로 설정할 수 있습니다.
초기화해야 하는 각 구성요소에 관해 별도의 콘텐츠 제공자를 정의하는 대신 앱 시작을 사용하면 단일 콘텐츠 제공자를 공유하는 구성요소 이니셜라이저를 정의할 수 있습니다.
이렇게 하면 앱 시작 시간이 크게 개선됩니다.
해당 내용 "초기화해야 하는 각 구성요소에 관해 별도의 콘텐츠 제공자를 정의하는 대신" 에서 궁금증이 생겼다.
'초기화 해야하는 각 구성요소를 ContentProvider 를 이용해야 했을까?'
'그러면 그냥 ContentProvider 를 사용해도 되는거 아닐까?'
2.2. ContentProvider 를 통한 구성요소 초기화
ContentProvider 는 Android 개발자라면 아직 못 본 사람은 있어도 한 번만 본 사람은 없다는 4대 컴포넌트에 해당한다.
ContentProvider 를 간단하게 말하면 데이터 엑세스를 관리하고 앱끼리 데이터를 주고 받는 방법을 제공해준다.
주로 사진 앱에서 이미지/동영상 등을 가져오거나 저장할 때 사용한 경험은 있어도 초기화가 필요한 구성요소를 초기화 하는 수단으로 사용할 생각을 못해봤다.
구글링 과정에서 생각보다 가까운곳에 구성요소 초기화 수단으로 ContentProvider 를 사용하고 있는 라이브러리가 있다는 것을 알았다.
TedPark 님께서 작성해주신 이제 더이상 Application에서 Library.init(this)같은 코드는 필요 없습니다 를 보면 Firebase 및 LeakCanary 에서 ContentProvider 를 사용하는 방식으로 Application 에서 init 하지 않고 application 을 가져와 사용하고 있었다.
2.3. ContentProvider 를 통한 구성요소 초기화가 가능한 이유
ContentProvider 의 onCreate()는 Application의 onCreate() 보다 먼저 실행되기 때문에 라이브러리 구성 요소에 application 정보를 전달하기에 무리가 없다.
실제로 애플리케이션의 시작지점인 main()
함수가 포함된 메인 클레스에 해당하는 ActivityThread.java
에서 handleBindApplication()
을 살펴보면 다음과 같다
<code />
@UnsupportedAppUsage
private void handleBindApplication(AppBindData data) {
//...생략
// don't bring up providers in restricted mode; they may depend on the
// app's custom Application class
if (!data.restrictedBackupMode) {
if (!ArrayUtils.isEmpty(data.providers)) {
installContentProviders(app, data.providers);
}
}
//...생략
try {
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
if (!mInstrumentation.onException(app, e)) {
throw new RuntimeException(
"Unable to create application " + app.getClass().getName()
+ ": " + e.toString(), e);
}
}
}
installContentProviders()
에서 ContentProvider 를 모두 찾아서 초기화 후onCreate()
를 하고 mInstrumentation.callApplicationOnCreate(app)
를 통해 Application
의 onCreate()
를 호출한다.
해당 코드는 AOSP 에서 확인 가능하다. [링크]
(https://github.com/aosp-mirror/platform_frameworks_base/blob/241e1a5caee61342e78a136dbf79e6841936e01d/core/java/android/app/ActivityThread.java#L7018)
또한 실제로 ContentProvider 안에서 application context 에 접근이 가능하기 때문에 초기에 설정해야하는 라이브러리 작업이 가능하다고 생각했다.
그리고 실제로 이러한 방식으로 만들어진 라이브러리는 개발자가 직접 .init() 을 호출하지 않아도 된다
2.4. ContentProvider 를 통한 구성요소 초기화 단점 1: 로딩 시간
바로 위에서 installContentProviders()
에서 ContentProvider 를 모두 찾아서 초기화 후onCreate()
를 한다는 사실을 알 수 있었다.
그러면 초기 궁금증의 대부분을 해소할 수 있다.
'초기화 해야하는 각 구성요소를 ContentProvider 를 이용해야 했을까?'
'그러면 그냥 ContentProvider 를 사용해도 되는거 아닐까?'
실제 코드를 바탕으로 보면 선언된 ContentProvider 를 모두 찾아서 초기화하기 때문에 앱 로딩 속도가 저하될 수 있다고 생각했다.
@Configuration 처럼 각 설정을 나누어 관리하면 ContentProvider 가 하는 역할 + 앱 초기화 역할 을 동시에 하는 다수의 ContentProvider 가 생성되고 그 만큼 앱 로딩 속도가 저하될 수 있다고 판단했다.
2.5. ContentProvider 를 통한 구성요소 초기화 단점 2: 초기화 순서 보장 X
해당 부분은 자세한 코드를 찾지 못했지만, 기본적으로 안드로이드에서 라이브러리 초기화 순서를 보장할 수 없다고 한다.
실제 SNS 로그인 라이브러리 내부에는 안드로이드 컴포넌트를 이용하는 경우도 많기 때문에 명확하게 언제 뭐가 초기화 된다고 말하기도 힘들 것 같다.
3. 마무리 하며...
실제 Jetpack Startup 의 적용하는 방법은 공식문서에 잘 나와있기 때문에 별도로 블로그에 기술하지 않기로 했다.
사실 문서화를 마치고, 블로그 글을 다 쓰고 가정을 해봤다.
만약, Jetpack Startup 라이브러리가 없는 상황에서 Application 객체 복잡도 증가를 해결하고자 했다면 나는 어떻게 했을까?
찾아낸 내용을 바탕으로 단순하게 ContentProvider 가 Application 전에 onCreate 되고 application context 에 접근 가능하다는 이유로 각 라이브러리 마다 책임을 분리하여 n개의 라이브러리를 초기화 하는 n개의 ContentProvider 를 만들지 않았을까 싶다.
그러고 초반과 달리 앱 로딩에 시간이 느려졌다고 생각이 들었다면, 이게 설마 내가 나누어둔 ContentProvider 로 인한 문제라고 생각도 못했을것 같다.
NextStep 책 초반에서 "프레임워크 소스단에서 검증" 이라는 부분을 읽으며 내가 겪는 문제를 더 깊게 분석하고 검증해야한다고 그렇게 배우고 써먹지도 못하는 상황이 발생했을 것을 생각하면 오히려 다행인가 싶기도 하다.
실제로 알아보며 다시금 자세한 내용을 더 깊게 공부해야겠다는 생각이 들었다.
문서화 과정에서 더욱 내가 도입하고자 한 내용을 팀원에게 설명하고 설득하는 과정에서 전문성을 갖춰야한다는 것 역시 알게 되었다.
'Android' 카테고리의 다른 글
[Android] 4.0 업데이트 이후 EditText만 보이지 않는 문제, EditText not renders in Layout editor (0) | 2020.10.13 |
---|---|
[Android/kotlin] RecyclerView clipToPadding (0) | 2020.05.04 |
[Android/kotlin] RecyclerView에 Divider 구분선 넣기 : ItemDecoration (2) | 2020.05.04 |
[Error](Android):java.net.SocketException: socket failed: EPERM (Operation not permitted) (0) | 2020.05.02 |
[Android] View & View Group의 개념 (0) | 2020.04.20 |