Android-Jetpack ViewModel

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

ViewModel 如何工作的

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

从图中能够知道 在onDestroy 的时候 viewModel 才是GG 的

那么 viewModel 是如何工作的呢??带着这个问题 ,吧这个问题拆解一下,分成3个问题在看一下

1.viewModel 创建对象的时候干啥了
2.viewModel 如何做到在onDestory 就clear的
3.viewModel 如何做到保存状态,

viewModel 创建对象的时候干啥了

下面是一个创建viewModel 的代码

1
val viewModel = ViewModelProvider(this).get(MyViewModel::class.java)

使用 ViewModelProvider 创建一个 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
25
26
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
//mViewModelStore 中map 存储了 viewmodel 对象
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 放入 map 中保存起来,
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}

ViewModelStore

在上面中 我们能够发 mViewModelStore 这个类中存储了 viewModel 继续看一下这个类

在 ComponentActivity 中能够找到

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

@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.");
}
//没有就创建 有就直接返回
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;
}

getViewModelStore 其实是 ViewModelStoreOwner 的接口

1
2
3
4
5
6
7
8
9
10

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

通过 getViewModelStore 这方法 我们能够看到 其他地方的创建

总结

到这里我们能够知道 在Activity或者Fragment 创建的时候,会生成一个 ViewModelStore 在生成 viewModel对象的时候,会存在 ViewModelStore 的map 中

viewModel 如何做到在onDestory 就clear的

看这个问题之前,先看一下 ViewModelStore 的代码

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
28
29
30
31
public class ViewModelStore {

//map 存储viewModel
private final HashMap<String, ViewModel> mMap = new HashMap<>();

//添加viewModel
final void put(String key, ViewModel viewModel) {
ViewModel oldViewModel = mMap.put(key, viewModel);
if (oldViewModel != null) {
oldViewModel.onCleared();
}
}

//获取viewModel
final ViewModel get(String key) {
return mMap.get(key);
}

Set<String> keys() {
return new HashSet<>(mMap.keySet());
}


//清理所有的viewModel
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
}

代码不多,很容易就明白所有的意思,看到最后的方法 clear 当viewModel clear的时候

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@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();
}

在看一下viewModel 生周期, 是不是最后onDestroy 的时候 会 onCleared

继续看一下 ComponentActivity 在构造方法中能够找到

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

public ComponentActivity() {
Lifecycle lifecycle = getLifecycle();
// lifecycle 自己添加了一个观察者
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
//观察到界面状态是 OnDestroy
if (event == Lifecycle.Event.ON_DESTROY) {
if (!isChangingConfigurations()) {
//看到这里,clear 了
getViewModelStore().clear();
}
}
}
});
}

总结

到这里就知道了 viewModel 也没有那么神秘,创建一个对象,被保存在map 中 ,在通过lifecycle 知道了界面销毁了,就给你clear

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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btn_intent.text = "跳转界面"

val viewModel = ViewModelProvider(this).get(MyViewModel::class.java)



viewModel.data.observe(this, {
Log.i("allens_tag", "main act data----> $it")
})

btn_add.setOnClickListener {
val value = viewModel.data.value
if (value != null) {
viewModel.data.setValue(value + 1)
}

}

btn_intent.setOnClickListener {
startActivity(Intent(this, TestAct::class.java))
}

}

override fun onDestroy() {
super.onDestroy()
Log.i("allens_tag", "main act destroy")
}

override fun onRetainCustomNonConfigurationInstance(): Any? {
Log.i("allens_tag", "Main onRetainCustomNonConfigurationInstance")
return super.onRetainCustomNonConfigurationInstance()
}

class MyViewModel : ViewModel() {

val data = MyMutableLiveData<Int>("Main").apply {
setValue(1)
}

override fun onCleared() {
Log.i("allens_tag", "main act vm cleared")
}
}
}

观察日志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//界面启动
2020-09-19 14:24:53.670 I: Main MyLiveData onActive
2020-09-19 14:24:53.670 I: main act data----> 1

//点击+1
2020-09-19 14:24:57.928 I: main act data----> 2
2020-09-19 14:24:58.076 I: main act data----> 3
2020-09-19 14:24:58.255 I: main act data----> 4
2020-09-19 14:24:58.468 I: main act data----> 5
//旋转屏幕
2020-09-19 14:25:02.159 I: Main MyLiveData onInactive
2020-09-19 14:25:02.166 I: Main onRetainCustomNonConfigurationInstance
2020-09-19 14:25:47.880 I: main act destroy
2020-09-19 14:25:48.317 I: Main MyLiveData onActive
2020-09-19 14:25:48.317 I: main act data----> 5

看一下上面的日志 有没有很好玩,其实当旋转屏幕以后,

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
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
//拿到创建新的Activity 之前的viewModel
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;
}

在看一下上面的

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

总结

viewModel 在你生命周期即将来凉了的时候,例如我在测试时候的 旋转屏幕。 将viewModel 救了下来,并且给到一个新的爸爸那里,这样不管宿主Act 咋样,viewModel 都能好好地活下来,一直到被clear 就真的凉了