费了不少脑细胞,把Lifecycle单拆出来整了一篇文章。那么接下来天然而然的就到了ViewModel,为了让系列像系列的样子,因此这里仍然是单独把ViewModel拿出来。java
你别说单独抽出来,还真有点干干巴巴,麻麻赖赖,一点都不圆润。那还说啥呢?盘它...android
一点点入坑JetPack:实战前戏NetworkBoundResource篇app
新官上任三把火,强敌面前秀三波。对于ViewModel来讲,它算是JetPack框架中堪当中枢的角色,说实话它实在很差单独去聊,更多的是和LiveData共进退。这里必须安利一下,ViewModel+LiveData的确很好用,甚至可能加上Room简直...飘了,拽了,感受本身个头都不矮了;疯了,狂了,敢在宇宙之间称王了....异步
碍于篇幅的缘由,这里单独聊ViewModel,后边会综合介绍展示其强大的战斗力...ide
关于ViewModel来讲,其实仍是蛮简单的。从ViewModel官方的描述来看ViewModel的存在,解决了俩大问题:post
咱们都知道,当咱们的Activity/Fragment由于某些因素被销毁重建时,咱们的成员变量便失去了意义。所以咱们经常须要经过 onSaveInstanceState()和onCreate()/onSaveInstanceState(Bundle)完成对数据的恢复(一般还要保证其正确的序列化)。而且对于大型数据来书,便有些乏力,好比:List、Bitmap...
而ViewModel就是解决此问题。
另外一个问题是Activity/Fragment常常须要进行一些异步操做。一旦涉及到异步,咱们都明白这里存在内存泄漏的可能性。所以咱们保证Activity/Fragment在销毁后及时清理异步操做,以免潜在的内存泄漏。
ViewModel并无自动帮咱们解决这个问题,而是经过onCleared()
交给咱们业务本身重写去处理。
关于ViewModel的使用,实在没啥好说的。实在是太简单了,一个简单的demo:
class MyViewModel : ViewModel() {
var name: String = "MDove"
}
// Activity中调用
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
val model = ViewModelProviders.of(this).get(MyViewModel::class.java)
// TODO model.name
}
}
复制代码
咱们只须要将想要被保存、被管理的变量,声明在ViewModel的实现类中便可。而后经过ViewModelProviders.of()/get()
拿到这个实例。就可能像往常同样自由的使用,而不须要担忧Activity/Fragment重建所带来的一系列问题。
文档在此处,有一个大大的警告:Caution: A ViewModel must never reference a view, Lifecycle, or any class that may hold a reference to the activity context.
为啥?从上述解决的问题来看,ViewModel很明显生命周期会比Activity要长,所以若是持有Activity相关实例,必然会带来内存泄漏。(那若是的确有业务须要咋整?使用AndroidViewModel(application)
便可。)
值得注意的一点:of方法须要传递一个Activity/Fragment。由于ViewModel须要与其生命周期绑定。既然能够传递一个Activity,那么咱们就可以猜到:是否是对于此Activity下的Fragment这个ViewModel也是可见的?
没错,正是如此。官方也做出了解读:Activity中的两个或多个Framgent须要相互通讯是很常见的,这个常见的痛点能够经过使用ViewModel对象来解决,这些Fragment能够共享ViewModel来处理通讯问题。
因此咱们在同Activity下,不一样的Fragment实例,能够直接经过传入activity,拿到一样的ViewModel实例,进而实现数据通信。
真的很方便...
若是咱们打开ViewModel的源码,咱们会发现...
public abstract class ViewModel {
@SuppressWarnings("WeakerAccess")
protected void onCleared() {
}
}
复制代码
就是一个抽象类,没错,整个ViewModel的设计就是很简洁,咱们往ViewModelProviders中继续看:
@NonNull
@MainThread
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);
}
复制代码
咱们能够看到在实例化ViewModelProvider中,须要传一个ViewModelStore,而这个ViewModelStore直接经过传入的FragmentActivity中拿,让咱们走进去看一看:
@NonNull
@Override
public ViewModelStore getViewModelStore() {
if (getApplication() == null) {
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't request ViewModel before onCreate call.");
}
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;
}
复制代码
咱们能够看到,这个ViewModelStore是在FragmentActivity中是一个mViewModelStore的变量。这个ViewModelStore是什么?从名字能够看出它是一个ViewModel的Store。
ViewModelStore的很简单,就是一个Map在后文中会展开。
最开始我看到这时,很懵。ViewModel是保证咱们重建后实例的惟一,但是这居然是一个成员变量,很明显重建后变量就没了?!...(PS:固然有这种疑问,是由于我本身蠢...)
怎么肥死,小老弟??...其实这里是没问题的,咱们仔细看一看,这个mViewModelStore赋值是经过这一行代码:
NonConfigurationInstances nc = (NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
mViewModelStore = nc.viewModelStore;
}
复制代码
没错,就是这行代码,保证了咱们重建后恢复原来的mViewModelStore,进而保证了咱们的ViewModel的惟一性。
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
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);
return (T) viewModel;
}
复制代码
mViewModelStore源码 -> ViewModelStore源码,很常见的Map存储操做
//
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);
}
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.onCleared();
}
mMap.clear();
}
}
复制代码
从ViewModel的使用上来讲,彷佛并无什么“船新的版本”...更多的是帮咱们搞定了一些现存的坑。的确是如此,但其实ViewModel更可能是带来了一种思想:数据驱动,也就是MVVM。
ViewModel做为中枢,担任了从数据源拿数据,交由LiveData通知UI层更新UI。用一张图来解释这种变革:
Google Sample为Repository的编写,提供了一个很巧妙的设计:NetworkBoundResource
。全类一共有120+的代码,却基于LiveData+ViewModel帮咱们约束了:从服务器取、从数据库取、网络获取失败,从数据库取...等等一系列网络请求、本地请求约数。
关于这个类的设计与用法,会在后续的实战篇一点点展开。没错,当你用上它们,你会爱上这款“游戏”。
今天的文章想聊的内容就到此结束了,更多的是ViewModel的一个引子。毕竟对于咱们来讲,我tm不须要知道这些,只须要告诉我怎么写就行。老夫写代码就是ctrl+c/v!
不着急,一点点来。后边我会把业务中正在运行的代码拿出来,作实战操做分析。饭要一口口的吃,文章要一篇篇的写...