Android ViewModel 浅析

343 阅读4分钟

ViewModel 是什么

官网 中给出的解释是:

类旨在以注重生命周期的方式存储和管理界面相关的数据,让数据可在发生屏幕旋转等配置更改后继续留存。

众说周知,当屏幕发生变化的时候,activity 会 onDestroy,然后在重新创建,这就会导致 之前保存的变量被重新赋值,变成初始状态。就像下面所示一样

而ViewModel 的作用就是保存这些数据

如何使用

导入ViewModel-lifecycle 依赖 在 声明依赖项 中可以查看最新版本

def lifecycle_version = "2.2.0"
// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
class ViewModelAct : AppCompatActivity() {

    companion object{
        const val TAG  = "viewModel-tag"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_viewmodel)

        //step2:获取 viewModel
        val viewModel = ViewModelProvider(this).get(TestViewModel::class.java)

        //step3:该咋用咋用
        tv_size.text = viewModel.viewModelSize.toString()
        btn_add.setOnClickListener {
            viewModel.viewModelSize++
            tv_size.text = viewModel.viewModelSize.toString()
        }
    }


    //step1:继承ViewModel
    class TestViewModel :ViewModel(){
        var viewModelSize = 0;
    }
}

ViewModel生命周期

放上一个官网的 ViewModel 的生命周期

ViewModel如何工作的

看一下我们创建ViewModel 的方法

ViewModelProvider(this).get(TestViewModel::class.java)

首先是实例化一个 ViewModelProvider

//ViewModelProvider
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
    this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
            ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
            : NewInstanceFactory.getInstance());
}

在构造方法中 通过 owner.getViewModelStore() 获取了 mViewModelStore

//ViewModelProvider
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
    mFactory = factory;
    mViewModelStore = store;
}

getViewModelStore 其实是一个接口

//ViewModelStoreOwner
public interface ViewModelStoreOwner {
    /**
     * Returns owned {@link ViewModelStore}
     *
     * @return a {@code ViewModelStore}
     */
    @NonNull
    ViewModelStore getViewModelStore();
}

在 Activity 中 能够看到 new 了一个 新的 ViewModelStore

//ComponentActivity
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.");
    }
    if (mViewModelStore == null) {
        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        if (nc != null) {
            // Restore the ViewModelStore from NonConfigurationInstances
            mViewModelStore = nc.viewModelStore;
        }
        if (mViewModelStore == null) {
            mViewModelStore = new ViewModelStore();
        }
    }
    return mViewModelStore;
}

在 Fragment 中 最终也是new 了一个 ViewModelStore

//Fragment
public ViewModelStore getViewModelStore() {
    if (mFragmentManager == null) {
        throw new IllegalStateException("Can't access ViewModels from detached fragment");
    }
    return mFragmentManager.getViewModelStore(this);
}
//FragmentManagerImpl
ViewModelStore getViewModelStore(@NonNull Fragment f) {
    return mNonConfig.getViewModelStore(f);
}
//FragmentManagerViewModel
ViewModelStore getViewModelStore(@NonNull Fragment f) {
    ViewModelStore viewModelStore = mViewModelStores.get(f.mWho);
    if (viewModelStore == null) {
        viewModelStore = new ViewModelStore();
        mViewModelStores.put(f.mWho, viewModelStore);
    }
    return viewModelStore;
}

接着看 ViewModelProvider(this).get(TestViewModel::class.java) get 方法

//ViewModelProvider
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
    String canonicalName = modelClass.getCanonicalName();
    if (canonicalName == null) {
        throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
    }
    return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}

//ViewModelProvider
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
    ViewModel viewModel = mViewModelStore.get(key);

    if (modelClass.isInstance(viewModel)) {
        if (mFactory instanceof OnRequeryFactory) {
            ((OnRequeryFactory) mFactory).onRequery(viewModel);
        }
        return (T) viewModel;
    } else {
        //noinspection StatementWithEmptyBody
        if (viewModel != null) {
            // TODO: log a warning.
        }
    }
    if (mFactory instanceof KeyedFactory) {
        viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
    } else {
        viewModel = (mFactory).create(modelClass);
    }
    //这里将viewModel put 到了  mViewModelStore
    mViewModelStore.put(key, viewModel);
    return (T) viewModel;
}

//ViewModelStore
private final HashMap<String, ViewModel> mMap = new HashMap<>();

final void put(String key, ViewModel viewModel) {
    //保存在map 中
    ViewModel oldViewModel = mMap.put(key, viewModel);
    if (oldViewModel != null) {
        oldViewModel.onCleared();
    }
}

{% note primary %} 通过 ViewModelProvider 将 ViewModel 保存在了 ViewModelStore 的map 中 {% endnote %}

ViewModel如何执行onCleared

看到 ViewModelStore 当执行了 clear 的时候 所有的ViewModel 都会执行 onCleared

//ViewModelStore
public final void clear() {
    for (ViewModel vm : mMap.values()) {
        vm.clear();
    }
    mMap.clear();
}
//ViewModel
@MainThread
final void clear() {
    mCleared = true;
    // Since clear() is final, this method is still called on mock objects
    // and in those cases, mBagOfTags is null. It'll always be empty though
    // because setTagIfAbsent and getTag are not final so we can skip
    // clearing it
    if (mBagOfTags != null) {
        synchronized (mBagOfTags) {
            for (Object value : mBagOfTags.values()) {
                // see comment for the similar call in setTagIfAbsent
                closeWithRuntimeException(value);
            }
        }
    }
    onCleared();
}

对于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()) {
                    //在这会成功触发
                    getViewModelStore().clear();
                }
            }
        }
    });
    //省略代码
}

对于Fragment

//FragmentController
public void dispatchDestroy() {
    mHost.mFragmentManager.dispatchDestroy();
}
//FragmentManagerImpl
public void dispatchDestroy() {
    //省略代码

    //执行下面的方法
    dispatchStateChange(Fragment.INITIALIZING);
    //省略代码
}
//FragmentManagerImpl
private void dispatchStateChange(int nextState) {
    try {
        mExecutingActions = true;
        moveToState(nextState, false);
    } finally {
        mExecutingActions = false;
    }
    execPendingActions();
}
//FragmentManagerImpl
void moveToState(int newState, boolean always) {
    //省略代码
    for (int i = 0; i < numAdded; i++) {
        Fragment f = mAdded.get(i);
        moveFragmentToExpectedState(f);
    }
     //省略代码
}
//FragmentManagerImpl
void moveFragmentToExpectedState(Fragment f) {
    //省略代码
    moveToState(f, nextState, f.getNextTransition(), f.getNextTransitionStyle(), false);
    //省略代码
}

//FragmentManagerImpl
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
                    boolean keepActive) {
    //省略代码
    if (beingRemoved || shouldClear) {
        mNonConfig.clearNonConfigState(f);
    }
    f.performDestroy();
    //省略代码
}

//FragmentManagerViewModel
void clearNonConfigState(@NonNull Fragment f) {
    //省略代码
    ViewModelStore viewModelStore = mViewModelStores.get(f.mWho);
    if (viewModelStore != null) {
        //最终也是在这里clear
        viewModelStore.clear();
        mViewModelStores.remove(f.mWho);
    }
    //省略代码
}

ViewModel 如何做到保存状态

先看到我们获取ViewModel 的地方

//ComponentActivity
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.");
    }
    if (mViewModelStore == null) {
        //获取上一个配置
        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        //如果配置不是空
        if (nc != null) {
            // Restore the ViewModelStore from NonConfigurationInstances
            //使用保存起来的viewModel
            mViewModelStore = nc.viewModelStore;
        }
        //如果上一次配置是空的
        if (mViewModelStore == null) {
            //创建新的ViewModel
            mViewModelStore = new ViewModelStore();
        }
    }
    return mViewModelStore;
}

//Activity
@Nullable
public Object getLastNonConfigurationInstance() {
    return mLastNonConfigurationInstances != null
            ? mLastNonConfigurationInstances.activity : null;
}

Android横竖屏切换时会触发onSaveInstanceState,而还原时会产生onRestoreInstanceState,但是Android的Activity类还有一个方法名为onRetainNonConfigurationInstancegetLastNonConfigurationInstance这两个方法

//ComponentActivity
@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;
    //viewModel 就被放在这里
    nci.viewModelStore = viewModelStore;
    return nci;
}

也就是说,在我们切换横竖屏的时候,系统会先将ViewModel 进行保存,之后,回复状态以后,从之前缓存的状态中获取,如此以后,我们的ViewModel 又回来了,还是原来的配方,还是原来的味道