- Android Jetpack開發:原理解析與應用實戰
- 黃林晴
- 844字
- 2022-07-05 09:43:59
3.5 原理小課堂
在3.3節中,已經分析了ViewModelProvider(this).get的內部方法,我們從中了解到創建的ViewModel對象都會被存在ViewModelStore中,如果創建的ViewModel對象已存在,則直接取出對象并返回,如果不存在則新建。
ViewModelProvider(this)中this的參數類型是ViewModelStoreOwner,由于在androidx.activity.ComponentActivity中實現了ViewModelStoreOwner接口并實現了getViewModelStore方法,因此開發者可以直接使用當前Activity的上下文this,主要代碼如下:
public class ComponentActivity extends androidx.core.app.ComponentActivity implements ViewModelStoreOwner{ ... @NonNull @Override public ViewModelStore getViewModelStore() { if (getApplication() == null) { throw new IllegalStateException("Your activity is not yet attached to the " + "Application instance. You can't request ViewModel before onCreate call."); } ensureViewModelStore(); return mViewModelStore; } ... }
接著來看getViewModelStore方法,此方法會進入ensureViewModelStore方法中,ensureViewModelStore方法的代碼如下:
void ensureViewModelStore() { if (mViewModelStore == null) { NonConfigurationInstances nc = (NonConfigurationInstances) getLastNonConfigurationInstance(); if (nc != null) { mViewModelStore = nc.viewModelStore; } if (mViewModelStore == null) { mViewModelStore = new ViewModelStore(); } } }
這里通過(NonConfigurationInstances) getLastNonConfigurationInstance()方法來獲取上一次的配置信息,NonConfigurationInstances中有viewModelStore對象,代碼如下:
static final class NonConfigurationInstances { Object custom; ViewModelStore viewModelStore; }
如果上一次配置信息不為空,就直接使用上一次的viewModelStore,如果為空則新建viewModelStore。在Activity旋轉屏幕被銷毀的時候,不僅會調用onSaveInstance-State方法,而且會調用onRetainNonConfigurationInstance方法,onRetainNonConfiguration-Instance方法的代碼如下:
public final Object onRetainNonConfigurationInstance() { Object custom = onRetainCustomNonConfigurationInstance(); ViewModelStore viewModelStore = mViewModelStore; if (viewModelStore == null) { 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; }
可以看到,在onRetainNonConfigurationInstance方法中對viewModelStore進行了存儲。當屏幕旋轉恢復的時候會通過getLastNonConfigurationInstance方法進行恢復。getLastNonConfigurationInstance方法的代碼如下:
@Nullable public Object getLastNonConfigurationInstance() { return mLastNonConfigurationInstances != null ? mLastNonConfigurationInstances.activity : null; }
所以在Activity旋轉屏幕的整個過程中,ViewModelStore對象保留了下來,通過ViewModelProvider(this).get方法獲取到的是同一個ViewModel實例,從而避免了由于屏幕旋轉而導致數據丟失的問題。
前面也提到了ViewModel雖然可以防止屏幕旋轉引起的數據丟失,但ViewModel并不能代替onSaveInstanceState方法,主要原因有如下兩點:
- onSaveInstanceState方法可以存儲少量的序列化數據,ViewModel可以存儲任意數據,只是使用時的限制不同。
- onSaveInstanceState可以達到數據持久化的目的,但是ViewModel不可以,使用場景不同。
為什么說ViewModel不能達到數據持久化的目的呢?因為當Activity被真正銷毀的時候,ViewModel會將資源進行回收,示例代碼如下:
getLifecycle().addObserver(new LifecycleEventObserver() { @Override public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) { if (event == Lifecycle.Event.ON_DESTROY) { ... if (!isChangingConfigurations()) { getViewModelStore().clear(); } } } });
從上面代碼可以看出,當對應的Activity被真正銷毀,即不是屏幕旋轉導致頁面被銷毀時,viewModelStore將會調用clear方法清理數據,所以ViewModel并不能達到數據持久化的目的。
可見,ViewModel并不能替代onSaveInstanceState方法,在實際開發中,讀者應選擇適合自己業務的方法,從而達到最佳體驗。
- C++面向對象程序設計(第三版)
- DBA攻堅指南:左手Oracle,右手MySQL
- Delphi程序設計基礎:教程、實驗、習題
- Visual Basic編程:從基礎到實踐(第2版)
- Python零基礎快樂學習之旅(K12實戰訓練)
- 信息技術應用基礎
- R Data Analysis Cookbook(Second Edition)
- SQL Server從入門到精通(第3版)
- 青少年信息學競賽
- 基于SpringBoot實現:Java分布式中間件開發入門與實戰
- C++編程兵書
- PrimeFaces Blueprints
- scikit-learn Cookbook(Second Edition)
- Java程序設計教程
- Drupal 8 Development Cookbook(Second Edition)