참고
https://uchun.dev/caution-when-using-a-fragment-viewLifecycleOwner/
Android 개발을 하다가 다음과 같은 exception Log를 보게 되었습니다.
java.lang.IllegalArgumentException: Cannot add the same observer with different lifecycles
발생한 이유는 LiveData의 Observer가 다른 owner에 포함이 되어 있다면 , LiveData는 위의 exception을 반환합니다.
즉, 하나의 activity에 있는 viewModel의 LiveData를 가져다 사용하는데, 아래와 같이 작성 하였더니
LiveData.observe(this, Observer{})
위의 IllegalArgumentException이 발생하였다. 이유는 activity에 포함된 viewmodel이고, 거기에 맞는 Lifecycle을 써야하는데 fragment lifecycle을 사용하여 발생한 문제 인것 같습니다.
그래서 this대신 다음과 같이 하면 좋습니다.
LiveData.observe(viewLifecycleOwner, Observer{})
로 하면 정상으로 동작하였습니다.
(일반적인 사용방법은 문제 없는데 Fragment에서 activity에 있는 Viewmodel을 끌어다 쓸 경우 이런 문제가 발생하는것 같습니다.
그리고 공부하면서 위의 viewLifecyclerOwner의 상세 코드를 보면서 viewLifecyclerOwner에 대해서 쪼금 공부를 해보았습니다.
@MainThread
@NonNull
public LifecycleOwner getViewLifecycleOwner() {
if (mViewLifecycleOwner == null) {
throw new IllegalStateException("Can't access the Fragment View's LifecycleOwner when "
+ "getView() is null i.e., before onCreateView() or after onDestroyView()");
}
return mViewLifecycleOwner;
}
즉, LifecycleOwener 도 exception이 발생할 수 있습니다. 이 mViewLifecycleOwner은 언제 null 처리되고 언제 생성이 될까요?
아래 코드를 보면
void performCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
mChildFragmentManager.noteStateNotSaved();
mPerformedCreateView = true;
mViewLifecycleOwner = new FragmentViewLifecycleOwner(this, getViewModelStore());
mView = onCreateView(inflater, container, savedInstanceState);
if (mView != null) {
// Initialize the view lifecycle
mViewLifecycleOwner.initialize();
// Tell the fragment's new view about it before we tell anyone listening
// to mViewLifecycleOwnerLiveData and before onViewCreated, so that calls to
// ViewTree get() methods return something meaningful
ViewTreeLifecycleOwner.set(mView, mViewLifecycleOwner);
ViewTreeViewModelStoreOwner.set(mView, mViewLifecycleOwner);
ViewTreeSavedStateRegistryOwner.set(mView, mViewLifecycleOwner);
// Then inform any Observers of the new LifecycleOwner
mViewLifecycleOwnerLiveData.setValue(mViewLifecycleOwner);
} else {
if (mViewLifecycleOwner.isInitialized()) {
throw new IllegalStateException("Called getViewLifecycleOwner() but "
+ "onCreateView() returned null");
}
mViewLifecycleOwner = null;
}
}
onCreateView 호출 이전에 FragmentViewLifecycleOwner 가 생성됩니다.
그러므로 onCreateView 에서 ViewLifecycleOwner 를 사용해도 문제가 없습니다.
그리고 null은 Fragment가 생성되지 않거나 아래 코드 처럼 Lifecycle.Event.ON_DESTROY가 발생하면 발생되는 것으로 보입니다. (명확하지는 않습니다. 열심히 뒤져봤는데 null 처리는 위의 performCreateView에서 밖에 찾지 못하였습니다.)
void performDestroyView() {
mChildFragmentManager.dispatchDestroyView();
if (mView != null && mViewLifecycleOwner.getLifecycle().getCurrentState()
.isAtLeast(Lifecycle.State.CREATED)) {
mViewLifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
}
mState = CREATED;
mCalled = false;
onDestroyView();
if (!mCalled) {
throw new SuperNotCalledException("Fragment " + this
+ " did not call through to super.onDestroyView()");
}
// Handles the detach/reattach case where the view hierarchy
// is destroyed and recreated and an additional call to
// onLoadFinished may be needed to ensure the new view
// hierarchy is populated from data from the Loaders
LoaderManager.getInstance(this).markForRedelivery();
mPerformedCreateView = false;
}
아무튼 onCreate전에 생성되기 때문에 언제든 써도 상관이 없는 것으로 보입니다.
'2023년 이전 > Android' 카테고리의 다른 글
Navigation을 사용항 경우 fragmentReulst (0) | 2021.12.05 |
---|---|
FragmentResult (0) | 2021.12.05 |
Corutine callbackFlow sendBlocking Deprecated (0) | 2021.12.05 |
A failure occurred while executing org.jetbrains.kotlin.gradle.internal.KaptWithoutKotlincTask$KaptExecutionWorkAction (0) | 2021.12.05 |
Module was compiled with an incompatible version of Kotlin (0) | 2021.12.05 |