官术网_书友最值得收藏!

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方法,在實際開發中,讀者應選擇適合自己業務的方法,從而達到最佳體驗。

主站蜘蛛池模板: 广西| 重庆市| 永德县| 碌曲县| 交口县| 通州市| 子洲县| 南江县| 开化县| 榆树市| 合水县| 广饶县| 侯马市| 淮滨县| 泉州市| 彩票| 武强县| 思茅市| 阿拉善右旗| 启东市| 理塘县| 嘉黎县| 汝城县| 婺源县| 阳信县| 荆门市| 连江县| 历史| 六盘水市| 新疆| 年辖:市辖区| 南通市| 广昌县| 丰顺县| 新乐市| 临朐县| 池州市| 马公市| 元阳县| 临汾市| 台北县|