博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android开发——架构组件LiveData源码解析
阅读量:4044 次
发布时间:2019-05-24

本文共 8089 字,大约阅读时间需要 26 分钟。

近期的业务代码中使用到了LiveData,研究了一下发现很好用,因此总结整理出了此篇学习笔记。希望各位多批评指正。

1. LiveData概述

简单地来说,LiveData就是一个持有数据的类。

  • LiveData中的数据可以被观察者订阅,当数据被修改时通知观察者。观察者包括Fragment、Activity以及Service等。
  • LiveData能够感知观察者的生命周期。只有在观察者处于激活状态(STARTED、RESUMED)才会收到数据更新;并在未激活时自动解注册观察者,避免崩溃,且减少内存泄露。
  • 当我们采用LiveData保存数据时,数据和组件的分离使得组件在ReCreate时保证数据不丢失。
需要注意的是:(1)当观察者从后台到前台来时,LiveData能够将最新的数据通知给观察者,保证数据实时更新;(2)组件在ReCreate时,会经历N个生命周期方法,但是ViewModel还是之前的对象。因此LiveData常结合VM使用。

2. LiveData的使用

LiveData的使用有两种方式,结合ViewModel使用LiveData对象或者直接继承LiveData类。

2.1 结合ViewModel使用LiveData对象

以一个简单的例子展示,使用LiveData子类MutableLiveData,维护一个String类型的数据:

public class MyViewModel extends ViewModel{    // Create a LiveData with a String    private MutableLiveData
mData; public MutableLiveData
getCurrentData() { if (mData == null) { mData = new MutableLiveData<>(); } return mData; }}

接着,创建并注册观察者:

public class LiveDataFragment extends Fragment{    private MyViewModel mViewModel;    @Override    public void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        //这里执行注册        mViewModel = ViewModelProviders.of(this).get(MyViewModel.class);        mViewModel.getCurrentData().observe(this, new Observer
() { @Override public void onChanged(@Nullable String data) { //LiveData数据变化后的回调 } }); }}

使用setValue更新LiveData中的数据

mViewModel.getCurrentData().setValue("yanxuan");

2.2 直接继承LiveData类

除了直接使用LiveData对象,还可以通过直接继承LiveData类来定义适合特定需求的LiveData。下面的例子使用LiveData简单地实现一个资源共享的需求。

public class MyLiveData extends LiveData
{ private static MyLiveData mData; private WeakReference
mContext; public static MyLiveData getInstance(Context context){ if (mData == null){ mData = new MyLiveData(context); } return mData; } private MyLiveData(Context context){ mContext = new WeakReference<>(context); } @Override protected void onActive() { super.onActive(); registerReceiver(); } @Override protected void onInactive() { super.onInactive(); unregisterReceiver(); } private void registerReceiver() { IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION); mContext.get().registerReceiver(mReceiver, intentFilter); } private void unregisterReceiver() { mContext.get().unregisterReceiver(mReceiver); } private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { mData.setValue(getWifiLevel(intent)); } };}

在onActive()和onInactive()方法中分别注册和反注册Wifi信号强度的广播,并且在广播接收器中更新数据。 在使用的时候就可以通过MyLiveData.getInstance().observe()方法来添加观察者对象和observer。

  • onActive(),当处于激活状态的observer个数从0到1时,该方法会被调用。
  • onInactive() ,当处于激活状态的observer个数从1变为0时,该方法会被调用。

3. LiveData源码解析

主要从以下三个方面进行分析:

  • 在Fragment/Activity中通过LiveData.observe()注册观察者
  • 根据Fragment/Activity生命周期的变化,实时移除观察者;或者从后台转到前台时通知观察者更新数据
  • 当调用LiveData的setValue()或postValue()方法后,通知观察者更新数据

3.1 注册观察者

public void observe(@NonNull LifecycleOwner owner, @NonNull Observer
observer) { if (owner.getLifecycle().getCurrentState() == DESTROYED) { // ignore return; } //将LifecycleOwner对象和Observer对象封装成LifecycleBoundObserver对象 LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer); //mObservers(一个类似Map的容器)的putIfAbsent()方法 //用于判断容器中的observer(key)是否有已经和wrapper(value)关联 //如果已关联则返回关联值,否则关联之后并返回wrapper。 ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper); if (existing != null && !existing.isAttachedTo(owner)) { throw new IllegalArgumentException("Cannot add the same observer" + " with different lifecycles"); } if (existing != null) { return; } //注册 owner.getLifecycle().addObserver(wrapper);}

首先将LifecycleOwner对象和Observer对象封装成LifecycleBoundObserver对象,LifecycleBoundObserver是一个内部类,它继承自ObserverWrapper,并实现了GenericLifecycleObserver,而GenericLifecycleObserver继承了LifecycleObserver接口。当组件生命周期变化时会通过onStateChanged()方法回调过来。

3.2 感知生命周期变化

通过上面的分析,观察者就是LifecycleBoundObserver对象,下面我们看一下LifecycleBoundObserver具体实现。

class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {    @NonNull final LifecycleOwner mOwner;    LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer
observer) { super(observer); mOwner = owner; } @Override boolean shouldBeActive() { return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED); } @Override public void onStateChanged(LifecycleOwner source, Lifecycle.Event event){ if (mOwner.getLifecycle().getCurrentState() == DESTROYED) { //DESTROYED状态下移除观察者 //该行代码会间接调用下面的detachObserver()方法 removeObserver(mObserver); return; } //判断是否处于actived状态,并将结果作为参数传递给activeStateChanged() activeStateChanged(shouldBeActive()); } @Override boolean isAttachedTo(LifecycleOwner owner) { return mOwner == owner; } @Override void detachObserver() { mOwner.getLifecycle().removeObserver(this); }}

当组件(Fragment/Activity)生命周期发生变化时,onStateChanged()方法会被调用。如果当前处于Lifecycle.State.DESTROYED时,会自动将观察者移除;若当前处于ACTIVE状态,则继续调用activeStateChanged()方法,该方法位于父类ObserverWrapper中:

void activeStateChanged(boolean newActive) {    //新状态和之前状态相同的情况,直接返回    if (newActive == mActive) {        return;    }    // immediately set active state, so we'd never dispatch anything to inactive owner    mActive = newActive;    boolean wasInactive = LiveData.this.mActiveCount == 0;    LiveData.this.mActiveCount += mActive ? 1 : -1;    if (wasInactive && mActive) {        onActive(); //空实现    }    if (LiveData.this.mActiveCount == 0 && !mActive) {        onInactive(); //空实现    }    if (mActive) {        dispatchingValue(this); //数据通知    }}

可以看到,若新状态和之前状态相同,则不进行不处理。 并且,当处于激活状态的observer个数从0到1时,调用onActive(); 当处于激活状态的observer个数从1到0时,调用onInactive()。

以上的onActive()和onInactive()都是空实现的方法,继承类可以选择去实现

最后调用的是dispatchingValue()进行数据变化时的消息通知,最终的回调代码如下。mObserver即为调用observe()注册时传入的Observer对象。

observer.mObserver.onChanged((T) mData);

3.3 改变数据后的通知逻辑

LiveData提供了两种改变数据的方法:在主线程调用的setValue()方法,以及在子线程中调用的postValue()方法。我们先看setValue()方法的具体实现:

protected void setValue(T value) {    assertMainThread("setValue");    mVersion++;    mData = value;    dispatchingValue(null);}

首先判断当前线程是否是主线程,不是就会抛出异常。将数据赋值给mData后,调用了dispatchingValue()进行数据通知,该方法3.2中已经讨论过了。

protected void postValue(T value) {    boolean postTask;    synchronized (mDataLock) {        postTask = mPendingData == NOT_SET;        //数据赋值给mPendingData,等待在主线程中使用        mPendingData = value;    }    if (!postTask) {return;}    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);}private final Runnable mPostValueRunnable = new Runnable() {    @Override    public void run() {        Object newValue;        synchronized (mDataLock) {            newValue = mPendingData;            mPendingData = NOT_SET;        }        //最终调用setValue()        setValue((T) newValue);    }};

在postValue()方法中,通过ArchTaskExecutor实现在主线程中执行mPostValueRunnable中的内容,而在mPostValueRunnable的run()中最终会调用setValue()方法来实现改变LiveData中的数据。

4. 总结

结合ViewModel的生命周期特点,LiveData很适合用于Fragment与Fragment之间的通信、Fragment与Activity之间的通信等。

需要注意的是,数据发送方和接收方传给方法ViewModelProviders.of()的对象必须一致,最终得到的才是同一个ViewModel对象。转载请注明出处:https://blog.csdn.net/SEU_Calvin/article/details/82256693

5. 踩坑

1. 当Fragment被detach再attach回来之后,如果你每次在onCreateView都会add新的observer实例,会导致添加多个observer。

这是因为Fragment在onDestroy才通知LiveData移除observers,若每次onCreateView都会add新的observer实例,这样就会导致数据更新时,LiveData会同时通知多个Observer,界面就会快速刷新多次。解决方式是当你在onCreateView方法中添加LiveData.observer(LifecycleOwner owner, Observer<T> observer)时,第一个参数使用Fragment.getViewLifecycleOwner()方法返回值。

2. 如果你使用了Fragment.getViewLifecycleOwner()作为参数, 但是同时自己又在onCreateView中处理了Fragmeng缓存, 导致不管如何切换fragment, 仅第一次才去add observer实例,这样的写法显然会导致attach回来之后observer失效。解决方法之一是改回Frament作为参数,或者每次onCreateView都保证去add一次observer实例。 

你可能感兴趣的文章
本科生的编程水平到底有多高
查看>>
AngularJS2中最基本的文件说明
查看>>
从头开始学习jsp(2)——jsp的基本语法
查看>>
使用与或运算完成两个整数的相加
查看>>
备忘:java中的递归
查看>>
DIV/CSS:一个贴在左上角的标签
查看>>
Solr及Spring-Data-Solr入门学习
查看>>
Vue组件
查看>>
python_time模块
查看>>
python_configparser(解析ini)
查看>>
selenium学习资料
查看>>
<转>文档视图指针互获
查看>>
从mysql中 导出/导入表及数据
查看>>
HQL语句大全(转)
查看>>
几个常用的Javascript字符串处理函数 spilt(),join(),substring()和indexof()
查看>>
javascript传参字符串 与引号的嵌套调用
查看>>
swiper插件的的使用
查看>>
layui插件的使用
查看>>
JS牛客网编译环境的使用
查看>>
9、VUE面经
查看>>