解密ViewModel是如何实现页面状态保存功能?
前言
互联网越来越卷,要求越来越高,我们不能仅仅停留在api的使用层面,要深入源码,阅读源码,分析源码,理解源码,最后模仿源码,才能快速提高 " 搬砖 "水平!
一,简介
ViewModel作为谷歌Jetpack重要组件之一,它不仅可以保存当前页面的状态,还能在页面配置更改后持久化保留相应状态。
二,使用步骤
1. 普通ViewModel
1.定义MainViewModel类继承ViewModel()
class MainViewModel:ViewModel() {
val mainLiveData = MutableLiveData<String>()
}
2.在activity中通过ViewModelProvider获取MainViewModel实例对象。
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val viewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).
get(MainViewModel::class.java)
viewModel.mainLiveData.observe(this){
}
}
通过定义一个MainViewModel类继承自ViewModel抽象类,然后再Activity中初始化MainViewModel。
2.提供Content的AndroidViewModel
- 如果需要在ManViewModel中使用context,MainViewModel需要继承AndroidViewModel。
class MainViewModel(application: Application):AndroidViewModel(application) {
val mainLiveData = MutableLiveData<String>()
}
2 .使用ViewModelProvider获取MainViewModel实例对象
val viewModel = ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory(application)).get(MainViewModel::class.java)
viewModel.mainLiveData.observe(this){
}
三,源码分析
1. Activity绑定
- Activity的父类ComponentActivity实现了ViewModelStoreOwner接口,
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
ContextAware,
LifecycleOwner,
ViewModelStoreOwner,
}
- ViewModelStoreOwner中定义了getViewModelStore方法用来提供ViewModelStore。
public interface ViewModelStoreOwner {
//返回一个ViewModelStore
@NonNull
ViewModelStore getViewModelStore();
}
- ViewModelStore中定义HashMap用来保存ViewModel实例。
public class ViewModelStore {
//定义HashMap集合存储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();
}
}
//根据key值获取对应的ViewModel
final ViewModel get(String key) {
return mMap.get(key);
}
Set<String> keys() {
return new HashSet<>(mMap.keySet());
}
/**
* 回收所有ViewModel并清空HashMap.
*/
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
}
-
由于ComponentActivity实现了ViewModelStoreOwner接口,在ComponentActivity中调用getViewModelStore可以获取ViewModel的存储类ViewModelStore,ViewModelStore中使用HashMap存储ViewModel,如果存储的ViewModel的key值相同,则删除oldViewModel旧的ViewModel,替换成最新的ViewModel。
-
ComponentActivity中使用Lifecycle对当前activity生命周期进行监听,并在on Destroy生命周期中对保存在ViewModelStore中的ViewModel进行清空释放。
public ComponentActivity() {
Lifecycle lifecycle = getLifecycle();
......................
.........................
//使用lifecycle对activity生命周期进行监听
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
//如果生命周期为onDestory
if (event == Lifecycle.Event.ON_DESTROY) {
// 清除context
mContextAwareHelper.clearAvailableContext();
//如果应用配置没有发生改变
if (!isChangingConfigurations()) {
//清除ViewModelStore中HashMap存储的ViewModel
getViewModelStore().clear();
}
}
}
});
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
//初始化ViewModelStore
ensureViewModelStore();
getLifecycle().removeObserver(this);
}
});
当ComponentActivity退出销毁时,会调用getViewModelStore().clear(), 清除ViewModelStore中HashMap存储的ViewModel,释放资源。
- 调用ensureViewModelStore进行ViewModelStore进行初始化。
void ensureViewModelStore() {
//如果存储类为null
if (mViewModelStore == null) {
//获取上一个保存的NonConfigurationInstances实例对象
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// 从 NonConfigurationInstances 恢复 ViewModelStore
mViewModelStore = nc.viewModelStore;
}
//否则创建新的ViewModelStore
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
}
static final class NonConfigurationInstances {
Object custom;
//成员变量用来保存ViewModelStore
ViewModelStore viewModelStore;
}
NonConfigurationIns tances是一个静态类,它有两个成员变量Object 和ViewModelStore ;如果ViewModelstore如果不存在,则将NonConfigurationIns tances的成员变量保存的ViewModelstore赋值给ViewModelStore 。
//获取上一次保存的数据
@Nullable
public Object getLastNonConfigurationInstance() {
return mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.activity : null;
}
mLastNonConfigurationInstances 是上一次保存的数据实例,当Activity被创建的时候,调用attach方法,mLastNonConfigurationInstances = lastNonConfigurationInstances; 当应用配置发生改变时,如屏幕旋转,会导致Activity重建,这个时候会获取上一次保存的mLastNonConfigurationInstances ,并取出其中存储的viewmodestore,最后得到ViewModel,直接从ViewModel中得到数据恢复界面列表。
2. ViewModel保存
- 使用ViewModelProvider创建ViewModel。
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
//创建ViewModelProvider对象
return new ViewModelProvider(activity);
}
- 由于当前activity实现ViewModelStoreOwner接口,所以可以通过getViewModelStore方法获取ViewModelStore对象。
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
//由于当前activity实现ViewModelStoreOwner接口,
//所以可以通过getViewModelStore方法获取ViewModelStore对象。
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
}
转载自:https://juejin.cn/post/7346465578734518298