本文记录Android Jetpack中
Architecture
部分的ViewModel以及工作原理。
Android Jetpack系列之ViewModel
Android Jetpack是一系列助力更容易打造卓越 Android 应用的工具和组件。这些组件能帮助您遵循最佳实践、免除编写繁复的样板代码并简化复杂任务,从而使您可以专注于最核心的代码逻辑。
Jetpack
中的架构指南由 Android
开发中四个关键领域中的一系列代码库和工具提供支持。它们分别是基础(Foundation)、架构(Architecture)、行为(Behavior)和 UI。每个 Jetpack
组件均可单独采用,但它们依然可以流畅地协作。其中 androidx.*
库与 Framework API
解耦,这能够提供向后兼容的同时,也能更频繁地更新。
本文记录Android Jetpack架构组件(Architecture)中的ViewModel。
ViewModel概述
ViewModel
用来管理UI交互的数据,它保存的数据不会因为Activity
配置改变而重新生成,比如屏幕旋转会重新触发onCreate()
,但是ViewModel
保存的数据不会丢失。
Activity
和Fragment
的生命周期是由Framework
管理,Framework
会在不在用户控制的情况下对Activity
、Fragment
进行销毁和重建。
如果Activity
、Fragment
销毁或者重建之后,存储在当中的数据将会丢失,简单的数据可以通过onSaveInstanceState()
跟onCreate()
来恢复,但是大数据,比如位图,或者一个列表却不适用,现在这些数据可以保存到ViewModel
中。
下面是屏幕旋转之后的对比
实现ViewModel
实现ViewModel
只需要继承ViewModel
即可,如:
1
2
3
4
5
6
7
8
9
10
11
class TextViewModel : ViewModel() {
var text: String? = null
get() {
if (field == null) {
field = asyncText()
}
return field
}
private fun asyncText(): String = "This is a Text"
}
然后再通过ViewModelProviders
来获取:
1
2
3
4
5
6
7
8
9
10
11
12
class ViewModelActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_view_model)
val textViewModel = ViewModelProviders.of(this)
.get(TextViewModel::class.java)
val modelTv = findViewById<TextView>(R.id.tv_model)
modelTv.text = textViewModel.text
}
}
如果Activity
重新创建,获取到的textViewModel
是同一个实例,当Activity
finished之后会调用ViewModel
的onCleared
,用于回收资源,下文追踪源码分析。
注意:ViewModel
不能有对View
的引用,或者其他对Activity Context
有引用的类。
如果需要用到Application Context
可以选择继承AndroidViewModel
。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class AndroidViewModel extends ViewModel {
@SuppressLint("StaticFieldLeak")
private Application mApplication;
public AndroidViewModel(@NonNull Application application) {
mApplication = application;
}
/**
* Return the application.
*/
@SuppressWarnings("TypeParameterUnusedInFormals")
@NonNull
public <T extends Application> T getApplication() {
//noinspection unchecked
return (T) mApplication;
}
}
ViewModel的生命周期
通常情况下会在Activity
的onCreate()
方法获取ViewModel
,此后无论onCreate()
调用多少次,获取到的ViewModel
都是同一个实例。
ViewModel源码分析
1
2
3
4
5
6
7
8
9
10
11
public abstract class ViewModel {
/**
* This method will be called when this ViewModel is no longer used and will be destroyed.
* <p>
* It is useful when ViewModel observes some data and you need to clear this subscription to
* prevent a leak of this ViewModel.
*/
@SuppressWarnings("WeakerAccess")
protected void onCleared() {
}
}
ViewModel
是一个抽象类,中间只有一个可选择实现的方法onCleared()
,该方法会在重复缓存当前ViewModel
到ViewModelStore
中或者HolderFragment
的onDestory()
被调用,用于回收资源。
ViewModelProviders.of(xxx).get(xxx)源码分析
对于上文中出现的代码:
1
val textViewModel = ViewModelProviders.of(this).get(TextViewModel::class.java)
ViewModelProviders.of(this)
的操作:
一共有4个重载方法
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
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull Fragment fragment) {
ViewModelProvider.AndroidViewModelFactory factory =
ViewModelProvider.AndroidViewModelFactory.getInstance(
checkApplication(checkActivity(fragment)));
return new ViewModelProvider(ViewModelStores.of(fragment), factory);
}
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
ViewModelProvider.AndroidViewModelFactory factory =
ViewModelProvider.AndroidViewModelFactory.getInstance(
checkApplication(activity));
return new ViewModelProvider(ViewModelStores.of(activity), factory);
}
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull Fragment fragment, @NonNull Factory factory) {
checkApplication(checkActivity(fragment));
return new ViewModelProvider(ViewModelStores.of(fragment), factory);
}
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity,
@NonNull Factory factory) {
checkApplication(activity);
return new ViewModelProvider(ViewModelStores.of(activity), factory);
}
该方法必须在主线程中调用,前两个方法不需要提供Factory
,会实现默认的factory。
1
ViewModelProvider.AndroidViewModelFactory factory = ViewModelProvider.AndroidViewModelFactory.getInstance(checkApplication(activity));
该方法会通过AndroidViewModelFactory#getInstance()
返回一个AndroidViewModelFactory
的单例,何为AndroidViewModelFactory
?
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
public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {
private static AndroidViewModelFactory sInstance;
/**
* Retrieve a singleton instance of AndroidViewModelFactory.
*
* @param application an application to pass in {@link AndroidViewModel}
* @return A valid {@link AndroidViewModelFactory}
*/
public static AndroidViewModelFactory getInstance(@NonNull Application application) {
if (sInstance == null) {
sInstance = new AndroidViewModelFactory(application);
}
return sInstance;
}
private Application mApplication;
/**
* Creates a {@code AndroidViewModelFactory}
*
* @param application an application to pass in {@link AndroidViewModel}
*/
public AndroidViewModelFactory(@NonNull Application application) {
mApplication = application;
}
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
//noinspection TryWithIdenticalCatches
try {
return modelClass.getConstructor(Application.class).newInstance(mApplication);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (InstantiationException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (InvocationTargetException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
}
}
return super.create(modelClass);
}
}
AndroidViewModelFactory
继承自NewInstanceFactory
。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static class NewInstanceFactory implements Factory {
@SuppressWarnings("ClassNewInstance")
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
//noinspection TryWithIdenticalCatches
try {
return modelClass.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
}
}
}
该类实现了Factory
接口,该接口只有一个方法create()
用于创建新的实例。
回到方法
1
ViewModelProvider.AndroidViewModelFactory factory = ViewModelProvider.AndroidViewModelFactory.getInstance(checkApplication(activity));
该方法通过AndroidViewModelFactory.getInstance(checkApplication(activity))
返回AndroidViewModelFactory
的单例。其中checkApplication(activity)
用于返回Activity/Fragment
绑定的Application
,如果没有绑定Application
则会抛出异常。
再回到最初的of
方法。
1
2
3
4
5
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
ViewModelProvider.AndroidViewModelFactory factory = ViewModelProvider.AndroidViewModelFactory.getInstance(checkApplication(activity));
return new ViewModelProvider(ViewModelStores.of(activity), factory);
}
1
return new ViewModelProvider(ViewModelStores.of(activity), factory);
该句代码中的ViewModelStores.of(activity)
会返回一个ViewModelStore
,该类用于存储ViewModel
。
ViewModelStores.of(activity)
有两个重载方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@NonNull
@MainThread
public static ViewModelStore of(@NonNull FragmentActivity activity) {
if (activity instanceof ViewModelStoreOwner) {
return ((ViewModelStoreOwner) activity).getViewModelStore();
}
return holderFragmentFor(activity).getViewModelStore();
}
@NonNull
@MainThread
public static ViewModelStore of(@NonNull Fragment fragment) {
if (fragment instanceof ViewModelStoreOwner) {
return ((ViewModelStoreOwner) fragment).getViewModelStore();
}
return holderFragmentFor(fragment).getViewModelStore();
}
这两个构造函数除了入参不一样,其他基本是一样的,先判断Activity/Fragment
是否实现了ViewModelStoreOwner
接口,实现该接口要求实现getViewModelStore()
方法并且返回一个ViewStore
。如果没有实现该接口则会调用holderFragmentFor(activity/fragment).getViewModelStore()
返回ViewModelStore()
。
holderFragmentFor(activity/fragment).getViewModelStore()
方法位于HolderFragment
中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static HolderFragment holderFragmentFor(FragmentActivity activity) {
return sHolderFragmentManager.holderFragmentFor(activity);
}
/**
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static HolderFragment holderFragmentFor(Fragment fragment) {
return sHolderFragmentManager.holderFragmentFor(fragment);
}
两个方法会返回HolderFragment
,sHolderFragmentManager
是HolderFragmentManager
用于管理HolderFragment
,其中的holderFragmentFor(Activity)
方法如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
HolderFragment holderFragmentFor(FragmentActivity activity) {
FragmentManager fm = activity.getSupportFragmentManager();
//通过HOLDER_TAG获取已经添加过的HolderFragment
HolderFragment holder = findHolderFragment(fm);
if (holder != null) {
return holder;
}
//mNotCommittedActivityHolders是一个Map,用于存储HolderFragment,key为Activity
holder = mNotCommittedActivityHolders.get(activity);
if (holder != null) {
return holder;
}
//用于判断是否注册ActivityLifeCycle回调,没有则注册,用于Activity销毁的时候移除对应的Activity以及触发对应ViewModel的onCleared()
if (!mActivityCallbacksIsAdded) {
mActivityCallbacksIsAdded = true;
activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks);
}
//创建新的HolderFragment并且为之设置TAG为HOLDER_TAG
holder = createHolderFragment(fm);
//将创建的HolderFragment放进mNotCommittedActivityHolders用于下次直接get()
mNotCommittedActivityHolders.put(activity, holder);
return holder;
}
再看holderFragmentFor(fragment).getViewModelStore()
就很清晰了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private ViewModelStore mViewModelStore = new ViewModelStore();
public HolderFragment() {
//当前Fragment绑定的Activity被recreate时,Fragment的onDestroy()和onCreate()不会调用
setRetainInstance(true);
}
@Override
public void onDestroy() {
super.onDestroy();
mViewModelStore.clear();
}
@NonNull
@Override
public ViewModelStore getViewModelStore() {
return mViewModelStore;
}
其实就是直接new ViewModelStore()
了,何为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
public class ViewModelStore {
private final HashMap<String, ViewModel> mMap = new HashMap<>();
final void put(String key, ViewModel viewModel) {
ViewModel oldViewModel = mMap.get(key);
if (oldViewModel != null) {
oldViewModel.onCleared();
}
mMap.put(key, viewModel);
}
final ViewModel get(String key) {
return mMap.get(key);
}
/**
* Clears internal storage and notifies ViewModels that they are no longer used.
*/
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.onCleared();
}
mMap.clear();
}
}
这个就很简单了。
获取到了ViewModelStore
,再回到最初的ViewModelProviders.of()
方法。
1
2
3
4
5
6
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
ViewModelProvider.AndroidViewModelFactory factory =
ViewModelProvider.AndroidViewModelFactory.getInstance(
checkApplication(activity));
return new ViewModelProvider(ViewModelStores.of(activity), factory);
}
下面这句返回一个ViewModelProvider
,该类没有父类,追踪源码可知。
1
2
3
4
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
this.mViewModelStore = store;
}
只是设置了mFactory
跟ViewModelStore
,上文分析可知这两个参数的由来。
再回到获取ViewModel
方法中的ViewModelProviders.of(this).get(TextViewModel::class.java)
分析get()
,上文可知of
返回的是ViewModelProvider
,所以直接打开ViewModelProvider#get()
方法。
1
2
3
4
5
6
7
8
@NonNull
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);
}
其中canonicalName
作为类的唯一标识。DEFAULT_KEY为android.arch.lifecycle.ViewModelProvider.DefaultKey
。点开重载方法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
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
//通过ViewModelStore来获取已存在的ViewModel
ViewModel viewModel = mViewModelStore.get(key);
//如果modelClass是上面viewModel的实例则直接返回
if (modelClass.isInstance(viewModel)) {
//noinspection unchecked
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
//通过Factory创建一个ViewModel,前文中的AndroidModelFacotry中的create()方法
viewModel = mFactory.create(modelClass);
//将当前ViewModel存储到ViewModelStore中
mViewModelStore.put(key, viewModel);
//noinspection unchecked
return (T) viewModel;
}
至此,ViewModelProviders.of(xx).get(xxx)
分析完毕。