ViewModel

像Activity,Fragment这类应用组件都有自己的生命周期并且是被Android的Framework所管理的。Framework可能会根据用户的一些操作和设备的状态对Activity或者Fragment进行销毁和重构。作为开发者,这些行为我们是无法干预的。

所以Activity或Fragment中的一些数据也会随着销毁而丢失,随着重构而重新生成。比如你的Activity中有个用户列表,当这个Activity重构的时候,新的Activity会重新获取用户列表。对于一些简单的数据,Activity可以使用onSaveInstanceState()方法,并从onCreate的bundle中重新获取。但这一方法途径仅仅适合一些简单的UI状态,对于用户列表这种庞大的数据并不适合。

还存在一个问题,Activity或者Fragment经常会做一些异步的耗时操作。随之就需要Activity和Fragment管理这些异步操作,并在自己被destroyed的时候清理它们,从而保证内存溢出这类问题的发生。这样的处理会随着项目扩大而变得十分复杂,一不留神,你的App就Crash了。

Activity和Fragment本身需要处理很多用户的输入事件并和操作系统打交道,所以当它们还要花时间管理它们的数据资源时,class文件就会变得异常庞大,然后就会造就出所谓的god activitiesgod fragments。这些UI控制类仅仅靠一个class就能处理相关的所有事务。简直跟上帝没啥两样。但这些类如果要进行单元测试的话,那就尴尬了。

所以就有了MVC,MVP这类设计模式,将视图与数据分离。今天讲到的ViewModel类的功能也一样,就是讲数据从UI中分离出来。并且当Activity或Fragment重构的时候,ViewModel会自动保留之前的数据并给新的Activity或Fragment使用。对于上面提到的用户列表的例子,ViewModel会为我们很好的管理这些数据。

public class MyViewModel extends ViewModel {
private MutableLiveData<List<User>> users;
public LiveData<List<User>> getUsers() {
if (users == null) {
users = new MutableLiveData<List<Users>>();
loadUsers();
}
return users;
} private void loadUsers() {
// do async operation to fetch users
}
}

接着在我们的Activity中就能这样使用了:

public class MyActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
model.getUsers().observe(this, users -> {
// update UI
});
}
}

这是当MyActivity被重构时,获得到的model实例是与重构前同一个,当MyActivity被销毁时,Framework会调用ViewModel的onCleared(),我们就可以在此方法中做资源的清理。

因为ViewModel的生命周期是和Activity或Fragment分开的,所以在ViewModel中绝对不能引用任何View对象或者任何引用了Activity的Context的对象。如果ViewModel中需要Application的Context的话,可以继承AndroidViewModel

Fragment之间的数据共享

在Activity中包好多个Fragment并且需要相互通信是非常常见的,这时就需要这些Fragment定义一些接口,然后让Activity来进行协调。而且这些Fragment还需要处理其他Fragment不可见或者还没有创建这些细节问题。

上面这个动点可以被ViewModel轻易解决,想象意向有这么个Activity,它包含FragmentA和FragmentB,其中A是用户列表,B是用户的详细数据,点击列表上的某个用户,在B中显示相应的数据。

看看使用ViewModel怎么处理这个问题:

public class SharedViewModel extends ViewModel {
private final MutableLiveData<Item> selected = new MutableLiveData<Item>(); public void select(Item item) {
selected.setValue(item);
} public LiveData<Item> getSelected() {
return selected;
}
} public class MasterFragment extends Fragment {
private SharedViewModel model;
public void onActivityCreated() {
model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item -> {
model.select(item);
});
}
} public class DetailFragment extends LifecycleFragment {
public void onActivityCreated() {
SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
model.getSelected().observe(this, { item ->
// update UI
});
}
}

这里要注意的是两个Fragment都使用了getActivity作为参数来获得ViewModel实例。这表示这两个Fragment获得的ViewModel对象是同一个。

使用了ViewModel的好处如下:

  • Activity不需要做任何事情,不需要干涉这两个Fragment之间的通信。
  • Fragment不需要互相知道,即使一个消失不可见,另一个也能很好的工作。
  • Fragment有自己的生命周期,它们之间互不干扰,即便你用一个FragmentC替代了B,FragmentA也能正常工作,没有任何问题。

ViewModel的生命周期

ViewModel的生命周期跟着传递给ViewModelProviderLifeCycle走,当生成了ViewModel的实例后,它会一直待在内存中,直到对应的LifeCycle彻底结束。下面是ViewModel与Activity对应的生命周期图:

Android官方架构组件介绍之ViewModel的更多相关文章

  1. Android官方架构组件介绍之ViewModel(三)

    ViewModel 像Activity,Fragment这类应用组件都有自己的生命周期并且是被Android的Framework所管理的.Framework可能会根据用户的一些操作和设备的状态对Act ...

  2. Android官方架构组件介绍之LifeCycle(一)

    Android官方架构组件介绍之LifeCycle 下面是官方提供的Android App开发的架构图: 从上图可以看到一些关键字:ViewModel,LiveData,Room等.其实看了上面视频的 ...

  3. Android官方架构组件介绍之LifeCycle

    Google 2017 I/O开发者大会于近日召开,在开发者大会上谷歌除了发布了Android O等一些新产品之外,也对Android代码的架构做出了一个官方的回应. Google 2017 I/O开 ...

  4. Android官方架构组件介绍之LiveData

    LiveData LiveData是一个用于持有数据并支持数据可被监听(观察).和传统的观察者模式中的被观察者不一样,LiveData是一个生命周期感知组件,因此观察者可以指定某一个LifeCycle ...

  5. Android官方架构组件介绍之LiveData(二)

    LiveData LiveData是一个用于持有数据并支持数据可被监听(观察).和传统的观察者模式中的被观察者不一样,LiveData是一个生命周期感知组件,因此观察者可以指定某一个LifeCycle ...

  6. Android官方架构组件介绍之应用(四)

    讲一个项目常见的功能,友盟统计功能 例如一个项目有很多多modlue,每个里面modlue都有Activity,Activity需要友盟统一,Fragment也需要友盟统计.一般做法就是继承一个Bas ...

  7. 改造 Android 官方架构组件 ViewModel

    前言 Android 官方架构组件在今年 5 月份 Google I/O 大会上被公布, 直到 11 月份一直都是测试版, 由于工作比较繁忙, 期间我只是看过类似的文章, 但没有在实际项目中使用过, ...

  8. Android官方架构组件指南

    此指南适用于那些曾经或现在进行Android应用的基础开发,并希望了解和学习编写Android程序的最佳实践和架构.通过学习来构建强大的生产级别的应用. 注意:此指南默认你对Android开发有比较深 ...

  9. Jetpack架构组件学习(2)——ViewModel和Livedata使用

    要看本系列其他文章,可访问此链接Jetpack架构学习 | Stars-One的杂货小窝 原文地址:Jetpack架构组件学习(2)--ViewModel和Livedata使用 | Stars-One ...

随机推荐

  1. MFC CreateWindow介绍

    CreateWindow 该函数创建一个重叠式窗口.弹出式窗口或子窗口.它指定窗口类,窗口标题,窗口风格,以及窗口的初始位置及大小(可选的).函数也指该窗口的父窗口或所属窗口(如果存在的话),及窗口的 ...

  2. websocke前世今生

    注:以下内容来自网上.本人经过加工整理. 1.问什么要用websocke? Browser已经支持http协议,为什么还要开发一种新的WebSocket协议呢?我们知道http协议是一种单向的网络协议 ...

  3. Python C :ctypes库

    >>> import ctypes >>> from ctypes import * >>> dir(ctypes) ['ARRAY', 'Arg ...

  4. ThinkPHP的ajaxReturn方法的使用

    ThinkPHP后端的代码如下: public function testAjax(){ $this->ajaxReturn(array('name'=>'z','age'=>18) ...

  5. xml & < 需要转义

    写了个request2XML的方法,每当数据中有'<'.'&'符号时,封装的XML就无法解析.发现了XML里的CDATA属性,问题迎刃而解!在XML文档中的所有文本都会被解析器解析. 只 ...

  6. C# 基础小知识之yield 关键字

    对于yield关键字我们首先看一下msdn的解释: 如果你在语句中使用 yield 关键字,则意味着它在其中出现的方法.运算符或 get 访问器是迭代器. 通过使用 yield 定义迭代器,可在实现自 ...

  7. Windows路径操作API函数学习

    前言 在VC++开发过程中,经常需要用到一些路径操作,比如拼需要的文件路径,搜索路径中的内容等等.Windows提供了一套关于路径操作的API帮助我们更好的执行这些操作. 路径截断与合并API Pat ...

  8. centos6.5 开发环境部署(nignx1.7.10+php5.4.38+mysql+ftp)

    一些命令和规则以及准备 本次流程再 DigitalOcean上的vps上通过 查看是否已经安装 rpm -qa | grep nginx 删除安装 #普通删除模式 rpm -e nginx #强力删除 ...

  9. 如何调用别人发布的WebService程序

    这篇经验会告诉我们如何调用别人发布的WebService,并且需要注意的事项.现在就拿获取天气预报的接口举例,因为文中不允许有链接,所以在下文图中有WebService链接的地址. 工具/原料   V ...

  10. POJ 1384 Piggy-Bank(完全背包)

    Description Before ACM can do anything, a budget must be prepared and the necessary financial suppor ...