- Jetpack系列文章
- Android Jetpack架构组件-Lifecycle使用
- Android Jetpack架构组件-LiveData使用
- Android Jetpack架构组件-ViewModel的使用及原理
- Android Jetpack架构组件-Paging介绍及实践
- Android Jetpack架构组件-Room基本使用
- Android Jetpack架构组件-Room数据库查询艺术
- Android Jetpack架构组件-Room升级
- Android Jetpack架构组件-WorkManager使用篇
- Android Jetpack架构-Paging自定义上拉加载更多
ViewModel顾名思义,是以感知生命周期的形式来存储和管理视图相关的数据。ViewModel主要有以下的特点:
1.当Activity被销毁时,我们可以使用onSaveInstanceState()方法恢复其数据,这种方法仅适用于恢复少量的支持序列化、反序列化的数据,不适用于大量数据,如用户列表或位图。而ViewModel不仅支持大量数据,还不需要序列化、反序列化操作。
2.Activity/Fragment(视图控制器)主要用于显示视图数据,如果它们也负责数据库或者网络加载数据等操作,那么一旦逻辑过多,会导致视图控制器臃肿,ViewModel可以更容易,更有效的将视图数据相关逻辑和视图控制器分离开来。
3.视图控制器经常需要一些时间才可能返回的异步调用,视图控制器需要管理这些调用,在合适的时候清理它们,以确保它们的生命周期不会大于自身,避免内存泄漏。而ViewModel恰恰可以避免内存泄漏的发生。
class MyViewModel : ViewModel() {
private var users: MutableLiveData<String>? = null
fun getUsers(): LiveData<String>? {
if (users == null) {
users = MutableLiveData<String>()
setName()
}
return users
}
fun setName() {
users?.value = "onexzgj"
}
}
getName方法中创建一个MutableLiveData,并通过MutableLiveData的setValue方法来更新数据。
/**
* ViewModel的使用
* @author onexzgj
*/
class ViewModelActivity : AppCompatActivity() {
lateinit var viewmodel: MyViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_view_model)
setTitle("ViewModel的使用")
viewModel = ViewModelProvider(this).get(MyViewModel::class.java)
viewModel.getUsers()?.observe(this, Observer {
Log.d("ViewModel", it)
})
}
}
通过获取一个MyViewModel的实例,然后配合LiveData就可以观察Name的变化,输出结果为:
如果重新创建了该 Activity,它接收的 MyViewModel
实例与第一个 Activity 创建的实例相同。当所有者 Activity 完成时,框架会调用 ViewModel
对象的 onCleared()
方法,以便它可以清理资源。
ViewModel对象存在的时间范围是获取ViewModel
时传递给 ViewModelProvider
的 Lifecycle
示例中则为Activity,之前创建ViewModel
的实例是通过
var viewModel = ViewModelProvider(this).get(MyViewModel::class.java)
ViewModel
将一直留在内存中,直到限定其存在时间范围的Lifecycle
永久消失:对于 Activity,是在 Activity 完成时;而对于 Fragment,是在 Fragment 分离时。
图 1 说明了 Activity 经历屏幕旋转而后结束的过程中所处的各种生命周期状态。该图还在关联的 Activity 生命周期的旁边显示了 ViewModel`的生命周期。此图表说明了 Activity 的各种状态。这些基本状态同样适用于 Fragment 的生命周期。
可以看到,通常在系统首次调用 Activity 对象的 onCreate()
方法时请求 ViewModel
。系统可能会在 Activity 的整个生命周期内多次调用 onCreate()
,如在旋转设备屏幕时。ViewModel
存在的时间范围是从您首次请求 ViewModel
直到 Activity 完成并销毁。
所以当前Activity的生命周期不断变化,经历了被销毁重新创建,而ViewModel的生命周期没有发生变化。
Activity 中的两个或更多 Fragment 需要相互通信是一种很常见的情况。想象一下主从 Fragment 的常见情况,假设您有一个 Fragment,在该 Fragment 中,用户从列表中选择一项,还有另一个 Fragment,用于显示选定项的内容。这种情况不太容易处理,因为这两个 Fragment 都需要定义某种接口描述,并且所有者 Activity 必须将两者绑定在一起。此外,这两个 Fragment 都必须处理另一个 Fragment 尚未创建或不可见的情况。
可以使用 ViewModel
对象解决这一常见的难点。这两个 Fragment 可以使用其 Activity 范围共享 ViewModel
来处理此类通信,如以下示例代码所示:
class SharedViewModel : ViewModel() {
val selected = MutableLiveData<Item>()
fun select(item: Item) {
selected.value = item
}
}
//主Fragemnt的逻辑
class MasterFragment : Fragment() {
private lateinit var itemSelector: Selector
private lateinit var model: SharedViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
model = activity?.run {
ViewModelProviders.of(this)[SharedViewModel::class.java]
} ?: throw Exception("Invalid Activity")
itemSelector.setOnClickListener { item ->
// Update the UI
}
}
}
class DetailFragment : Fragment() {
private lateinit var model: SharedViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
model = activity?.run {
ViewModelProviders.of(this)[SharedViewModel::class.java]
} ?: throw Exception("Invalid Activity")
model.selected.observe(this, Observer<Item> { item ->
// Update the UI
})
}
}
请注意,这两个 Fragment 都会检索包含它们的 Activity。这样,当这两个 Fragment 各自获取 ViewModelProvider
时,它们会收到相同的 SharedViewModel
实例(其范围限定为该 Activity)。
此方法具有以下优势:
SharedViewModel
约定之外,Fragment 不需要相互了解。如果其中一个 Fragment 消失,另一个 Fragment 将继续照常工作。要讲解原理,我们需要先从一个点入手,那就是第2节例子中的:
viewmodel = ViewModelProvider(this).get(MyViewModel::class.java)
因为我们是在Activity中调用的,因此this的值为Activity,我们还可以在Fragment中调用上面的方法,那么this的值为Fragment,因此ViewModelProviders(this)构造方法,我们以在Activity中调用为例。
跟踪到androidx.lifecycle.ViewModelProvider代码示例如下所示:
private final Factory mFactory;
private final ViewModelStore mViewModelStore;
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory() //注释1
: NewInstanceFactory.getInstance());
}
public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
this(owner.getViewModelStore(), factory);
}
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
}
可以看到在构造函数中,相当于实例化了Factory和ViewModelStore对象,因为ViewModelActivity
间接继承子ComponentActivity
,由于ComponentActivity实现了HasDefaultViewModelProviderFactory
,即这里factory
为HasDefaultViewModelProviderFactory
,我们再查看注释1处的getDefaultViewModelProviderFactory()
方法的实现,这里以
跟踪到androidx.activity.ComponentActivity中的具体代码如下所示:
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
LifecycleOwner,
ViewModelStoreOwner,
HasDefaultViewModelProviderFactory,
...
{
@Override
public ViewModelStore getViewModelStore() {
...
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;
}
@Override
public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
...
if (mDefaultFactory == null) {
//注释2
mDefaultFactory = new SavedStateViewModelFactory(
getApplication(),
this,
getIntent() != null ? getIntent().getExtras() : null);
}
return mDefaultFactory;
}
通过查看getDefaultViewModelProviderFactory()方法,里面间接调用了androidx.lifecycle.SavedStateViewModelFactory中SavedStateViewModelFactory(…)构造方法,接下来查看SavedStateViewModelFactory()的具体实现
@SuppressLint("LambdaLast")
public SavedStateViewModelFactory(@NonNull Application application,
@NonNull SavedStateRegistryOwner owner,
@Nullable Bundle defaultArgs) {
mSavedStateRegistry = owner.getSavedStateRegistry();
mLifecycle = owner.getLifecycle();
mDefaultArgs = defaultArgs;
mApplication = application;
mFactory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
在这里可以看到mApplication和mFactory的初始化,而mFactory是通过ViewModelProvider.AndroidViewModelFactory.getInstance(application)的实现,可以看到具体的实现方式如下,得到了一个AndroidViewModelFactory工厂。
@NonNull
public static AndroidViewModelFactory getInstance(@NonNull Application application) {
if (sInstance == null) {
sInstance = new AndroidViewModelFactory(application);
}
return sInstance;
}
到这里可以将ViewModelProvider(this)这部分分析完了,即初始化了一个mFactory和ViewModelStore对象,
接着回头看ViewModelProvider.get方法的实现:
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
String canonicalName = modelClass.getCanonicalName();//1
if (canonicalName == null) {
throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
}
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);//2
}
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
ViewModel viewModel = mViewModelStore.get(key);//3
if (modelClass.isInstance(viewModel)) {
//noinspection unchecked
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
viewModel = mFactory.create(modelClass);
mViewModelStore.put(key, viewModel);
//noinspection unchecked
return (T) viewModel;
}
注释1处得到类的名称,对这个名称进行字符串拼接,作为注释2处方法的参数,DEFAULT_KEY的值为: “androidx.lifecycle.ViewModelProvider.DefaultKey”。
因此,注释3处的key值实际上就是”androidx.lifecycle.ViewModelProvider.DefaultKey”+类名。根据这个key值从ViewModelStore获取ViewModel(ViewModel的实现类)。如果ViewModel能转换为modelClass类的对象,直接返回该ViewModel。
否则会通过Factory创建一个ViewModel,并将其存储到ViewModelStore中。这里的Factory指的是AndroidViewModelFactory,它在ViewModelProvider创建时作为参数传进来。
到此为止,我们已经知道了ViewModel的实现类是如何创建的了。
当创建完ViewModel的实现类后,在第2小节我们还会调用如下代码。
viewmodel.getUsers()?.observe(this, Observer {
Log.d("ViewModel", it)
})
model.getName()会返回一个MutableLiveData,接着调用了MutableLiveData的observe方法,这个在Android Jetpack架构组件-LiveData使用 这篇文章中讲过,就不再赘述。
项目中所有的示例代码及Jetpack全套框架均已上传至OnexZgj_Github
该仓库为演示Jetpack的组件的仓库,分别对Lifecyele、LiveData、ViewModel、Room的介绍和使用
##详细介绍文章
Android Jetpack架构组件-Lifecycle使用
Android Jetpack架构组件-LiveData使用
Android Jetpack架构组件-ViewModel的使用及原理
Android Jetpack架构组件-Paging介绍及实践
Android Jetpack架构组件-Room基本使用
Android Jetpack架构组件-Room数据库查询艺术
Android Jetpack架构组件-Room升级