ViewModel 爲什麼被設計出來,解決了什麼問題
1.不會因爲屏幕旋轉而銷燬,減少了維護狀態的工作。
2.由於在作用域內單一實例的特性,使得多個fragment之間可以方便通信,並且維護同一個數據狀態。
3.完善了MVVM架構,使得解耦更加純粹。
ViewModel的銷燬
activity的銷燬:
public ComponentActivity() {
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
if (!isChangingConfigurations()) {
// 銷燬ViewModel
getViewModelStore().clear();
}
}
}
});
}
最終在調用了ViewModelStore類中的clear()方法:
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
ViewModelScope是什麼?
viewModelScope 是一個 ViewModel 的 Kotlin 擴展屬性。它能在ViewModel銷燬時 (onCleared() 方法調用時) 退出。所以只要使用了 ViewModel,就可以使用 viewModelScope在 ViewModel 中啓動各種協程,而不用擔心任務泄漏。
ViewModel 是否涉及序列化與反序列化?
是不涉及的,數據不涉及跨進程通信,都是直接在當前應用進程的內存中傳遞。
一個 Activity 中是否支持多個 ViewModel ?
準確的說,是支持多個 key 不一致的 ViewModel 對象,因爲 ViewModelStore 的本質是一個維護 Key-ViewModel 的
map 容器。
Activity橫豎屏切換時爲什麼viewModel能保存持有的數據
在Activity實例中重寫onRetainCustomNonConfigurationInstance、getLastNonConfigurationInstance方法,打印數據,當橫豎屏旋轉屏幕時,會打印這兩個方法,一個是activity銷燬時調用,一個是activity重建時調用,這兩個方法是ComponentActivity透給activity可以自己實現的方法,用於給子類保存臨時數據用的。
override fun onRetainCustomNonConfigurationInstance(): Any? {
Log.i("minfo", "onRetainCustomNonConfigurationInstance")
return super.onRetainCustomNonConfigurationInstance()
}
override fun getLastNonConfigurationInstance(): Any? {
Log.i("minfo", "getLastNonConfigurationInstance")
return super.getLastNonConfigurationInstance()
}
進入ComponentActivity類的方法:
static final class NonConfigurationInstances {
Object custom;
ViewModelStore viewModelStore;
}
@Override
@Nullable
public final Object onRetainNonConfigurationInstance() {
Object custom = onRetainCustomNonConfigurationInstance();
ViewModelStore viewModelStore = mViewModelStore;
if (viewModelStore == null) {
// No one called getViewModelStore(), so see if there was an existing
// ViewModelStore from our last NonConfigurationInstance
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
viewModelStore = nc.viewModelStore;
}
}
if (viewModelStore == null && custom == null) {
return null;
}
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = viewModelStore;
return nci;
}
public Object onRetainCustomNonConfigurationInstance() {
return null;
}
橫豎屏切換調用onRetainNonConfigurationInstance,獲取了頁面的mViewModelStore,將mViewModelStore保存到NonConfigurationInstances的實例中。
Activity類中方法:
@Nullable
public Object getLastNonConfigurationInstance() {
return mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.activity : null;
}
橫豎屏切換恢復時調用getLastNonConfigurationInstance,獲取activity中的mLastNonConfigurationInstances實例,獲取其中的viewmodelStore,賦值給activity的viewmodelstore。
爲什麼橫豎品切換明明調用了activity的onDestroy,viewmodel卻沒有調用clear呢?
如果是手動銷燬頁面,會走viewmodel的clear方法清除數據。但是如下代碼進行了判斷,當activity調用destroy,如果是因爲橫豎屏切換,這裏就不會讓viewModel清除數據。
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
// Clear out the available context
mContextAwareHelper.clearAvailableContext();
// And clear the ViewModelStore
if (!isChangingConfigurations()) {
getViewModelStore().clear();
}
}
}
});
參考:
https://blog.csdn.net/OneDeveloper/article/details/115049760
https://blog.csdn.net/chuhe1989/article/details/109805408