Koin - Activity Scope
강성우, 30 July 2020
Koin에서 Activity scope를 적용한 경험을 정리하였다. 이 내용을 잘 응용하면 custom scope를 적용하는 대 에도 무리가 없을것 으로 생각 된다.
1. Module definition
module()DSL 함수를 이용하여 모듈을 정의 하는데 scope()를 이용해 Custom scope를 적용 한다. scope()함수 에 포함될 함수들의 구현들은 Custom scope의 라이프사이클에 동기화 되어 적용 된다.
scope()함수에는 적용할 Custom scope에 대해 named()함수를 이용하여 이름을 적용해 퀄리파이어 처럼 사용할 수 있다. 이는 스코프를 구분하는데 사용 된다. 아래 예제코드의 경우 named<T>()와 같이 제네릭을 사용하여 클래스 자체를 이름으로 적용 하였다.
val activityModules = module {
scope(named<PokemonSearchActivity>()) {
scoped<PokemonNavigationHelper> {
PokemonNavigationHelperImpl(get<PokemonSearchActivity>())
}
viewModel { PokeSearchViewModel(get(), get(), get(), get()) }
viewModel { PokeDetailViewModel(get(), get(), get()) }
}
}
위 예제코드의 모듈 정의를 보면 다음과 같다.
PokemonSearchActivity의 라이프사이클을 갖는 커스텀 스코프를 적용한 모듈을 정의 한다.PokemonSearchActivityscope에서는PokemonNavigationHelper인스턴스가 해당 scope에만 사용 가능 하다.PokeSearchViewModel, PokeDetailViewModel또한 해당 scope에서만 사용 가능 하다.
2. Scope declare
scope를 적용할 Activity에서 scope에 대한 라이프사이클을 적용해야 한다.
class PokemonSearchActivity : AppCompatActivity() {
// module에서 정의한 Activity scope를 얻는다.
private val activityScope =
getKoin().getOrCreateScope(POKEMON_SEARCH_ACTIVITY_SCOPEID, named<PokemonSearchActivity>())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.pokesearch_activity)
// 얻은 scope를 통해서 이 Activity를 사용할수 있음을 선언한다.
// 선언된 인스턴스가 이미 존재 할 경우 `overrdie = true`로 설정 하여 재정의 할 수 있도록 해준다.
activityScope.declare(this, override = true)
}
override fun onDestroy() {
// Activity가 종료될 시점에 Acitivty의 scope도 같이 종료 시켜준다.
activityScope.close()
super.onDestroy()
}
}
정리하면, 모듈에서 정의한 custom scope를 특정 인스턴스의 create - destroy 각 시점에 맞추어 선언해주고, 종료시켜주는 것 이다.
custom scope를 생성할때 사용되는 POKEMON_SEARCH_ACTIVITY_SCOPEID는 Scope에 대한 ID로서 예제에서는 문자열로 되어 있다.
3. Examples
예를 들어 위 모듈에서 scope에 적용했던 ViewModel을 주입받는 방법을 보면 아래와 같다.
class PokemonSearchFragment : BaseFragment() {
private val activityScope = getKoin().getScope(POKEMON_SEARCH_ACTIVITY_SCOPEID)
private val vm: PokeSearchViewModel by lazy {
activityScope.getViewModel<PokeSearchViewModel>(requireParentFragment())
}
// ...
}
Fragment에서는 scope에 대한 인스턴스를 POKEMON_SEARCH_ACTIVITY_SCOPEID라는 scope id(문자열)을 통해 얻고 이를 이용해서 getViewModel()DSL 함수를 이용해 ViewModel인스턴스를 주입받음을 알수있다.
