一、ViewModel的特点:
- ViewModel 可以实现Activity与fragment之间的数据共享,以及同一个Activity中多个Fragment之间的数据共享
- ViewModel可以感知Activity的生命周期,actiivty ondestory前,会调用viewModel的onCleared()方法 供我们来释放资源
二、viewModel是如何实现 数据共享和感知生命周期的
我们知道ViewModel 是一个抽象类,自定义ViewModel是需继承ViewModel类.
public abstract class ViewModel {
@Nullable
private final Map<String, Object> mBagOfTags = new HashMap<>();
private volatile boolean mCleared = false;
/**
* 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() {
}
@MainThread
final void clear() {
mCleared = true;
//省略代码...
onCleared();
}
TranslateViewModel.kt
如TranslateViewModel 继承自ViewModel类
class TranslateViewModel constructor() : ViewModel(){
}
初始化如TranslateViewModel对象,却不能直接使用new TranslateViewModel()来初始化该对象。
需要调用ViewModelProviders.of(this).get(TranslateViewModel::class.java) 方法
错误的初始化方法:
mViewModel = new TranslateViewModel()
正确的初始化方法:
mViewModel = ViewModelProviders.of(this).get(TranslateViewModel::class.java)
2.1 如何实现数据共享的
关键点就在于
mViewModel = ViewModelProviders.of(this).get(TranslateViewModel::class.java)
2.1.1、ViewModelProviders.of() 返回的是一个ViewModelProvider
public class ViewModelProviders {
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
return of(activity, null);
}
public static ViewModelProvider of(@NonNull FragmentActivity activity,
@Nullable Factory factory) {
Application application = checkApplication(activity);
if (factory == null) {
factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
return new ViewModelProvider(activity.getViewModelStore(), factory);
}
}
2.1.2、ViewModelProvider用于提供一个ViewModel,构建一个ViewModelProvider,需要两个参数
- ViewModelStore 提供ViewModel的存储和复用机制
- ViewModelProvider.Factory - ViewModel的生产工厂,用于生产一个新的ViewModel对象
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
}
我们看一下ViewModelProvider.get()方法,此方法用户返回一个viewModel对象
public class 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);
}
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
//关键代码
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(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);
}
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
}
可以发现
(1)会先去mViewModelStore 查找,有没有XXX::class 对应的ViewModel对象,如果有,则直接返回
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
(2)如果mViewModelStore中没有 目标ViewModel对象,则直接利用ViewModelProvider.Factory 生产一个新的ViewModel对象,同时保存到mViewModelStore中,以供下次复用。
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
} else {
viewModel = (mFactory).create(modelClass);
}
mViewModelStore.put(key, viewModel);
2.1.3、ViewModelStore 用于存储复用ViewModel对象,
同时FragmentActivity 和Fragment都继承了ViewModelStoreOwner ,可以获取到viewModelStore对象。
public class ViewModelStore {
private final HashMap<String, ViewModel> mMap = new HashMap<>();
final void put(String key, ViewModel viewModel) {
ViewModel oldViewModel = mMap.put(key, viewModel);
if (oldViewModel != null) {
oldViewModel.onCleared();
}
}
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();
}
}
public interface ViewModelStoreOwner {
/**
* Returns owned {@link ViewModelStore}
*
* @return a {@code ViewModelStore}
*/
@NonNull
ViewModelStore getViewModelStore();
}
总结:
至此原理清楚了。
- 每个Activity或者Fragment当中持有一个mViewModelStore,存储和复用activity当中用到的ViewModel
- 创建ViewModel对象时,如果传入的是同一个Activity,那么ViewModelProvider中的ViewModelStore就是同一个对象。
- ViewModelProvider调用get(XXXViewModel::class) ,获取ViewModel时,通过Activity的ViewModelStore实现了ViewModel的共享。
即 传入的Activity是同一个的前提下,多次调用下面的方法,获取到的ViewModel是同一个对象。
mViewModel = ViewModelProviders.of(this).get(TranslateViewModel::class.java)
2.2 如何感知Activity的生命周期的
首先明确一点,ViewModel只能感知activity生命周期中的onDestory()。在activity销毁前,执行viewModel的clear(回调onCleared(),进行资源的释放)。
那么我们来看activity中是在什么时候触发viewModel的clear()操作的
public class FragmentActivity extends ComponentActivity implements XXX{
}
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
LifecycleOwner,
ViewModelStoreOwner,
SavedStateRegistryOwner,
OnBackPressedDispatcherOwner {
public ComponentActivity() {
Lifecycle lifecycle = getLifecycle();
//noinspection ConstantConditions
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();
}
}
}
});
}
}
可以看到,在基类ComponentActivity的构造方法中,注册了LifeCycleObserver,检测到Lifecycle.Event.ON_DESTROY事件之后,会自动调用getViewModelStore().clear()
public class ViewModelStore {
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.onCleared();
}
mMap.clear();
}
}
网友评论