안녕하세요 점냥입니다 :)
지난 포스팅에 이어서 이번에는 ViewModel을 사용해서 Fragment 내에서 데이터를 공유하는 방법에 대해서 알아보겠습니다. 이번 내용은 코드로서 보다는 개념 위주로 설명이 될 것 같아요!
우선 ViewModel이란 Android Jetpack 라이브러리 중 하나로 비즈니스 로직과 데이터들을 저장해 두는 Holder class인데요. MVVM이 대중화가 되고 Activity보다 수명이 긴 장점으로 데이터의 복원/ 저장이 보다 간편해 많이 사용하고 있는 Class입니다. ViewModel의 자세한 내용은 이곳에서 확인해주세요
ActivityViewModel로 Fragment 끼리 데이터 공유
@AndroidEntryPoint
class SignUpCodeFragment : BaseFragment<FragmentSignUpCodeBinding>() {
private val viewModel: SignUpViewModel by activityViewModels()
...
}
Fragment ktx 의존성을 추가하면 activityViewModels 이름의 extenstion 함수를 사용할 수 있어요. 해당 함수는 동일한 Activity 내에 존재하는 Fragment들은 동일한 ViewModel을 생성할 수 있도록 보장해 줍니다.
ViewModelStore
public class ViewModelStore {
private final HashMap<String, ViewModel> mMap = new HashMap<>();
final void put(String key, ViewModel viewModel) {
ViewModel oldViewModel = mMap.put(key, viewModel);
if (oldViewModel != null) {
oldViewModel.onCleared();
}
}
final ViewModel get(String key) {
return mMap.get(key);
}
Set<String> keys() {
return new HashSet<>(mMap.keySet());
}
/**
* Clears internal storage and notifies ViewModels that they are no longer used.
*/
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
}
어떻게 가능한 걸까요? 답은 viewModelStore에 있습니다.
생성된 ViewModel은 ViewModelStore 내에 존재하는 Map 객체에 저장이 돼요. Activity, Fragment의 상위 클래스들은 ViewModelStoreOnwer를 구현하고 있고 ViewModelStore도 각각 가지고 있습니다. 그로 인해 Activity, Fragment 각각 고유한 ViewModel을 생성할 수 있었는데요.
@MainThread
public inline fun <reified VM : ViewModel> Fragment.activityViewModels(
noinline factoryProducer: (() -> Factory)? = null
): Lazy<VM> = createViewModelLazy(
VM::class, { requireActivity().viewModelStore },
... }
)
activityViewModels 함수는 Fragment의 ViewModelStore를 사용하는 것이 아닌 Activity ViewModelStore를 사용하는 것으로 Fragment 끼리 동일한 ViewModel을 가질 수 있도록 만들었습니다 :)
ParentFragment와 ChildFragment 간의 데이터 공유
간혹 Parent Fragment와 Child Fragment 끼리 데이터를 공유하고 싶을 수도 있습니다. 이때 ActivityViewModel로 데이터를 공유할 수 있지만 좀 더 범위를 좁혀 ParentFragment 내에서만 Child Fragment끼리 ViewModel을 공유하게 만들 수도 있습니다.
inline fun <reified VM : ViewModel> Fragment.parentViewModels(
noinline ownerProducer: () -> ViewModelStoreOwner = { requireParentFragment() },
): Lazy<VM> {
return viewModels(ownerProducer)
}
activityViewModel의 방식을 참고하여 ParentFragment의 viewModelStoreOwner를 주입시켜 Child Fragment 끼리 동일한 ViewModel을 공유하도록 구현할 수 있습니다 :)
이후 데이터 주고받는 방식은 ActivityViewModel과 동일하기 때문에 생략하겠습니다!
'Android > Common' 카테고리의 다른 글
[Android] minSdk, compileSdk, targetSdk (0) | 2023.09.25 |
---|---|
[Android] Radius 올바르게 적용하기 (0) | 2023.05.24 |
[Android] Fragment에서 데이터 외부로 전달시키는 방법 - Callback (0) | 2022.12.03 |
[Android] Very Long Vector Path 해결 (0) | 2022.11.18 |
[Android] 디버그 앱, 출시 앱 분리하기 (4) | 2022.11.12 |