앱의 각 VIewModel을 대상으로 정의된다. 이 범위내에서 시작되는 모든 코루틴들은 ViewModel이 삭제되면 전부 취소된다.
Coroutine이 ViewModel이 살아있는 경우에만 존재해야할 경우에 유용하다.
class MyViewModel: ViewModel() {
init {
viewModelScope.launch {
// Coroutine that will be canceled when the ViewModel is cleared.
}
}
}
/**
*[CoroutineScope] tied to this[LifecycleOwner]'s[Lifecycle].
*
* This scope will be cancelled when the[Lifecycle] is destroyed.
*
* This scope is bound to
* [Dispatchers.Main.immediate][kotlinx.coroutines.MainCoroutineDispatcher.immediate].
*/
class MyFragment: Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewLifecycleOwner.lifecycleScope.launch {
val params = TextViewCompat.getTextMetricsParams(textView)
val precomputedText = withContext(Dispatchers.Default) {
PrecomputedTextCompat.create(longTextContent, params)
}
TextViewCompat.setPrecomputedText(textView, precomputedText)
}
}
}
Fragment 를 사용하다보면 onCreateView() 함수이 호출 될 때, view 를 생성하고
onViewCreated() 함수에서 이미 생성한 view를 사용하는 경우가 많습니다.
viewLifeCycleOwner 는 onCreateView() 에서 생성되는 view의 LifeCycle 를 뜻 합니다.
그래서 onCreateView() ~ onDestoryView() 라이프 사이클을 가집니다.
fun Fragment.launchAndRepeatOnLifecycle(
state: Lifecycle.State = Lifecycle.State.STARTED,
action: suspend CoroutineScope.() -> Unit
) {
lifecycleScope.launch{
viewLifecycleOwner.repeatOnLifecycle(state){
action()
}
}
}
위 함수에는 몇가지 문제점이 있습니다.
state를 파라미터로 받고있는데 이를 관장하는 scope는 lifecycleScope입니다.
/**
*<li>{@linkLifecycle.Event#ON_CREATE created} after {@link#onViewStateRestored(Bundle)}</li>
*<li>{@linkLifecycle.Event#ON_START started} after {@link#onStart()}</li>
*<li>{@linkLifecycle.Event#ON_RESUME resumed} after {@link#onResume()}</li>
*<li>{@linkLifecycle.Event#ON_PAUSE paused} before {@link#onPause()}</li>
*<li>{@linkLifecycle.Event#ON_STOP stopped} before {@link#onStop()}</li>
*<li>{@linkLifecycle.Event#ON_DESTROY destroyed} before {@link#onDestroyView()}</li>
*</ol>
lifecycleScope는 onViewStateRestored다음으로 불리게 됩니다.
따라서 Lifecycle.State.CREATED로 설정하여도
onAttach - onCreateView - onViewCreated - onViewStateRestored - onStart - …순으로 불리게 되며 onViewCreated보다 늦게 불리게 됩니다.
즉 만약에 내가 onViewCreated에서 데이터를 세팅할때 모든 flow가 emit된 후에 Flow를 collect한다면 아무런 데이터를 받을수 없는 상황이 생깁니다.
(StateFlow나 SharedFlow(replay=1)을 이용하면 현재의 값을 방출해주므로 해결되지만 side effect가 발생할 가능성이 있다.)
따라서 우리는 이걸 변형해서 사용할 필요가 있다.
fun Fragment.launchAndRepeatOnLifecycle(
state: Lifecycle.State = Lifecycle.State.STARTED,
action: suspend CoroutineScope.() -> Unit
) {
viewLifecycleOwner.lifecycleScope.launch{
viewLifecycleOwner.repeatOnLifecycle(state){
action()
}
}
}
기존의 fragment의 lifecycle을 보는것이 아니라 viewLifecycle을 보게 만들었다.
viewLifeCycleOwner는
💡 * {@link#getViewLifecycleOwner() lifecycle of the Fragment's View}. ** This will be set to the new {@linkLifecycleOwner} after {@link#onCreateView} returns a * non-null View and will set to null after {@link#onDestroyView()}.
onCreateView이후에 생성되며 onDestroyView까지 유지가 된다.
따라서 위의 Util함수를 사용할때 onCreate에서 생성해서 onDestroy까지 유지하길 원해서
Lifecycle.State.CREATED로 넣는다면
viewLifecycleOwner의 생명주기를 따르게끔 만들어야 할 것이다.