共计 4767 个字符,预计需要花费 12 分钟才能阅读完成。
ViewModel
ViewModel 的职责是为 Activity 或者 Fragment 管理数据.
如何获取一个 ViewModel?
继承 ViewModel 或者 AndroidViewModel
class MyViewModel : ViewModel(){
}
// 如果你需要在 ViewModel 中使用上下文对象, 可以继承 AndroidViewModel
class MyViewModel2(var application : Application) : AndroidViewModel(){
}
如果继承 AndroidViewModel, 构造函数必须有一个 Application 类型的参数, 并且只能是 Application, 而不是其子类.
在 Activity 或者 Fragment 中获取 MyViewModel 实例对象
val myViewModel = ViewModelProviders.of(activity/fragment).get(MyViewModel::class.java)
ViewModel 的唯一性
如果一个 Activity/Fragment 未被销毁, 那么多次获取 ViewModel, 得到的是同一个实例对象. 从源码中去分析这个逻辑. 先看 ViewModelPoviders.of() 这个方法, 返回一个 ViewModelProvider 对象
public static ViewModelProvider of(@NonNull Fragment fragment) {
return of(fragment, null);
}
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
return of(activity, null);
}
这里只看 Activity 的
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(ViewModelStores.of(activity), factory);
}
看一下 ViewModelProvider 这个构造函数
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
this.mViewModelStore = store;
}
当获取到 ViewModelProvider 对象后, 调用其 get 方法获取到 MyViewModel 的实例对象看一下 get 方法
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) {
// 从 ViewModelStore 中获取 ViewModel 对象
ViewModel viewModel = mViewModelStore.get(key);
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;
}
从这里可以看到是从 ViewModelStore 中获取 ViewModel 对象. 在 ViewModelStore 中封装了一个 HashMap 对象. 如果 HashMap 对象中存储了 ViewModel 对象, 就直接复用, 如果 ViewModel 对象未创建, 就重新创建后存储在 HashMap 中.
要保证 ViewModel 是唯一的,ViewModelStore 就必须是唯一的. 看一下 ViewModelStore 是如果获取到的. 在给 ViewModelProvider 传参数时调用了 ViewModelStores.of(activity), 看一下这一步做了什么?
//ViewModelStores.java
public static ViewModelStore of(@NonNull FragmentActivity activity) {
if (activity instanceof ViewModelStoreOwner) {
return ((ViewModelStoreOwner) activity).getViewModelStore();
}
return holderFragmentFor(activity).getViewModelStore();
}
查看安卓源码发现,support 包下的 Fragment 和 FragmentActivity 都继承了 ViewModelStoreOwner, 自然要实现其方法.
//FragmentActivity
public ViewModelStore getViewModelStore() {
if (this.getApplication() == null) {
throw new IllegalStateException(“Your activity is not yet attached to the Application instance. You can’t request ViewModel before onCreate call.”);
} else {
if (this.mViewModelStore == null) {
FragmentActivity.NonConfigurationInstances nc = (FragmentActivity.NonConfigurationInstances)this.getLastNonConfigurationInstance();
if (nc != null) {
this.mViewModelStore = nc.viewModelStore;
}
if (this.mViewModelStore == null) {
this.mViewModelStore = new ViewModelStore();
}
}
return this.mViewModelStore;
}
}
可以看出, 对于一个未销毁的 Activity 或者 Fragment, 其 ViewModelStore 对象是唯一的. 那么其存储的 ViewModel 对象也是唯一的.
ViewModel 的特点
由上面可知,Activity 或者 Fragment 未被销毁,ViewModel 是唯一的, 那么其保存的数据也是不变的, 当 Activity 发生了屏幕旋转等变化时, 仍旧可以复用 ViewModel 中的数据.
不要持有 View 层的引用
ViewModel 内部不要持有 View 层的引用, 比如 Activity 或者 Fragment. 可以和 LiveData 结合使用
生命周期
由图可看出,Activity 重建前后,ViewModel 保持不变.
LiveData
LiveData 持有数据, 并可在给定的生命周期内被观测. 继承关系如下:[LiveData] ^- [MutableLiveData] ^- [MediatorLiveData MutableLiveData 对外暴露 setValue 和 postValue.MediatorLiveData 观察别的 LiveData. 并能将 active/inactive 状态传递给它所观察的 LiveData 对象.
postValue 与 setValue
postValue 可以从后台线程更新数据,setValue 只能在主线程中更新数据. 如果同时调用这两个方法,postValue 设置的数据会覆盖 code>setValue 设置的数据.postValue 是通过 ArchTaskExecutor 来实现在主线程中更新数据. 在 ArchTaskExecutor 中使用主线程的 Handler.
observeForever 与 removeObserver
如果一个观察者通过 observeForever 被添加, 这个观察者会被认为一直处于激活状态, 任何数据更新都会立即通知到它. 因此需要手动调用 removeObserver 去移除它.
onActive 与 onInactive
Lifecycle
v4 包下的 SupportActivity 和 Fragment 默认都实现了 LifecycleOwner(<font color=’#ff0000′ size=’6px’>API27+</font>), 并且都默认初始化了 lifeCycle 实例
//LifecycleOwner
public interface LifecycleOwner {
/**
* Returns the Lifecycle of the provider.
*
* @return The lifecycle of the provider.
*/
@NonNull
Lifecycle getLifecycle();
}
//supportActivity
public class SupportActivity extends Activity implements LifecycleOwner, Component {
private LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
public Lifecycle getLifecycle() {
return this.mLifecycleRegistry;
}
}
public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener, LifecycleOwner,
ViewModelStoreOwner {
LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
@Override
public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}
}
public class LifecycleRegistry extends Lifecycle {
//………
}
google 官方 MVVM 架构图
由图可以看出, 不管数据从哪里来, 最终要汇聚到数据仓库,LiveData 观察的是数据仓库的变化. 并且 ViewModel 中可以定义多个 LiveData.