LiveData#
用途#
可观察的数据存储类
关键: 是一种数据类型
优势#
可感知其他组件的生命周期,如Activity、Fragment、Service
只通知处于活跃状态的观察者;非活跃的观察者不会收到通知
确保界面实时响应数据的变化—数据变化,会进入Observer#onStateChange回调
不会发生内存泄漏–Observer会绑定到Lifecycle,其关联的组件销毁后,Observer会自我释放
不会因为Activity停止导致crash–Observer处于非活跃状态,它不会收到任何LiveData事件
数据始终保持最新状态–从非活跃状态变为活跃状态,Observer会收到最新的数据,后台Activity返回前台后会立刻接收最新的数据
兼容系统配置更改–由于设备更改重新创建了Activity、Fragment,Observer会立即收到livedata的最新数据,这一切都不需要额外开发代码
共享资源–使用单例模式扩展LiveData,以便于在整个App内共享数据。具体用法参考本节基本用法#共享值
生命周期#
- onActive
- onInactive
数据类型#
名称 | 用途 |
---|---|
LiveData | 抽象类,定义了setValue、postValue方法 |
MediatorLiveData | LiveData的实现类,组合多个LiveData进行观察,也可以作为一个Livedata被Observer观察 |
MutableLiveData | LiveData的实现类,泛型中声明即将存储的数据类型 |
基本用法#
livedata一般都存放于viewmodel类中,所以使用前先初始化viewmodel
1 | nameViewModel = ViewModelProviders.of(this).get(NameViewModel.class); |
LiveData封装在ViewModel里
1 | public class NameViewModel extends ViewModel { |
设置值#
通过viewmodel#getUserName拿到livedata,再通过lviedata的setvalue方法设置数值
1 | nameViewModel.getUserName().setValue("jordan " + aLong + " 号"); |
订阅值#
通过viewmodel#getUserName拿到livedata,再通过lviedata的observer方法观察数值的改变
1 | Observer<String> nameObserver = new Observer<String>() { |
问:postValue与setValue区别
如果处于主线程中,可以使用 setValue(T)
方法更新 LiveData
对象
如果在子线程中,可以使用postValue(T)
方法来更新 LiveData
对象
问:不考虑页面生命周期,如果先设置值,后observer,会进入onchange回调吗?
答:会进入onchange回调
组合订阅#
看一下组合订阅的用法
- 两次addSource,为MediatorLiveData传入了2个LiveData实现类,同时为每个livedata设置了Observer
- MediatorLiveData设置观察者Observer
- 在任意一个livedata收到onChanged回调时,触发MediatorLiveData的set方法,设置值
- MediatorLiveData的observer会收到上一步MediatorLiveData#set方法的通知
1 | MediatorViewModel mediatorViewModel = ViewModelProviders.of(this).get(MediatorViewModel.class); |
共享值.#
定义一个单例LiveData
1 | public class StockLiveData extends LiveData<BigDecimal> { |
其他Fragment、Activity可以这样使用它
1 | public class MyFragment extends Fragment { |
在多个Activity、Fragment的任意一处通过StockLiveData#get
得到的返回值都是全局唯一的。
疑问#
- livedata存放在App进程还是系统进程?App进程销毁后重新创建能恢复之前的数据吗?
- 永久的Observer有什么用?
问题3:value不变,调用setValue,会进入Observer的回调吗?
答:会,LiveData不会判断相等
问题4:postvalue是如何通知主线程刷新的?
使用Handler.createAsync
创建了异步Handler,持有主线程的Looper
使用异步Handler发出的Message都是异步消息,结合view.requestLayout设置的消息屏障,可以让MessageQueue优先执行异步消息,后执行同步消息
下图是我梳理的postValue的执行过程,使用Handler发出异步消息,优先于主线程的同步消息执行。这样可以做到在下一次界面刷新之前(每隔16.6ms)设置数据。
问题5:postValue一定会进入observer回调吗?
答:不一定,取决于许多因素
- 生命周期的状态是否处于活跃状态:
started
或resumed
。如果处于这两种状态,则会进入observer#onChanged
回调;如果不处于,则不会进入回调