Android ViewModel 浅析

ViewModel 是什么

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

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

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

如何使用

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

1
2
3
def lifecycle_version = "2.2.0"
// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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 的方法

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

首先是实例化一个 ViewModelProvider

1
2
3
4
5
6
//ViewModelProvider
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}

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

1
2
3
4
5
//ViewModelProvider
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
}

getViewModelStore 其实是一个接口

1
2
3
4
5
6
7
8
9
10
//ViewModelStoreOwner
public interface ViewModelStoreOwner {
/**
* Returns owned {@link ViewModelStore}
*
* @return a {@code ViewModelStore}
*/
@NonNull
ViewModelStore getViewModelStore();
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//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

1
2
3
4
5
6
7
//Fragment
public ViewModelStore getViewModelStore() {
if (mFragmentManager == null) {
throw new IllegalStateException("Can't access ViewModels from detached fragment");
}
return mFragmentManager.getViewModelStore(this);
}
1
2
3
4
//FragmentManagerImpl
ViewModelStore getViewModelStore(@NonNull Fragment f) {
return mNonConfig.getViewModelStore(f);
}
1
2
3
4
5
6
7
8
9
//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 方法

1
2
3
4
5
6
7
8
//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);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//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;
}
1
2
3
4
5
6
7
8
9
10
//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();
}
}

通过 ViewModelProvider 将 ViewModel 保存在了 ViewModelStore 的map 中

ViewModel如何执行onCleared

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

1
2
3
4
5
6
7
//ViewModelStore
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

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

1
2
3
4
//FragmentController
public void dispatchDestroy() {
mHost.mFragmentManager.dispatchDestroy();
}
1
2
3
4
5
6
7
8
//FragmentManagerImpl
public void dispatchDestroy() {
//省略代码

//执行下面的方法
dispatchStateChange(Fragment.INITIALIZING);
//省略代码
}
1
2
3
4
5
6
7
8
9
10
//FragmentManagerImpl
private void dispatchStateChange(int nextState) {
try {
mExecutingActions = true;
moveToState(nextState, false);
} finally {
mExecutingActions = false;
}
execPendingActions();
}
1
2
3
4
5
6
7
8
9
//FragmentManagerImpl
void moveToState(int newState, boolean always) {
//省略代码
for (int i = 0; i < numAdded; i++) {
Fragment f = mAdded.get(i);
moveFragmentToExpectedState(f);
}
//省略代码
}
1
2
3
4
5
6
//FragmentManagerImpl
void moveFragmentToExpectedState(Fragment f) {
//省略代码
moveToState(f, nextState, f.getNextTransition(), f.getNextTransitionStyle(), false);
//省略代码
}
1
2
3
4
5
6
7
8
9
10
//FragmentManagerImpl
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
//省略代码
if (beingRemoved || shouldClear) {
mNonConfig.clearNonConfigState(f);
}
f.performDestroy();
//省略代码
}
1
2
3
4
5
6
7
8
9
10
11
//FragmentManagerViewModel
void clearNonConfigState(@NonNull Fragment f) {
//省略代码
ViewModelStore viewModelStore = mViewModelStores.get(f.mWho);
if (viewModelStore != null) {
//最终也是在这里clear
viewModelStore.clear();
mViewModelStores.remove(f.mWho);
}
//省略代码
}

ViewModel 如何做到保存状态

先看到我们获取ViewModel 的地方

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//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;
}
1
2
3
4
5
6
//Activity
@Nullable
public Object getLastNonConfigurationInstance() {
return mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.activity : null;
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//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 又回来了,还是原来的配方,还是原来的味道