【Android】LiveData 源码分析

前言

LiveData其实已经不是一个新鲜的东西了,我是在使用MVVM框架的时候开始接触到LiveData的,LiveData用起来确实很方便。

LiveData是一个具有感知组件生命周期的类,如Activity、Fragment、Service,只要和LiveData进行了绑定,LiveData就能感知到它们的生命周期。

LiveData的基本使用我们就不讲了,因为它的使用非常简单,不懂的话网上一搜一大把。

那么,LiveData有什么好处呢?

1、监听与其绑定的界面的生命周期,因此使用LiveData我们就不需要手动管理它的生命周期了

2、组件能及时响应LiveData的数据变化,组件总能拿到LiveData的最新数据。当然,被绑定的组件响应LiveData是有一定的前提的,那就是LiveData数据发生变化 且 组件处于活跃状态

也就是说,LiveData数据即使发生了变化,也不一定会响应onChanged函数,因为它必须要求LiveData数据所在的界面处于活跃状态,才会响应onChanged函数。

3、 生命周期自动解绑,因为其能够在组件销毁的时候自动解绑,大大降低了应用产生内存泄露的概率

LiveData确实能解决内存泄漏问题,但是如果我们使用不当,其实还是会出现内存泄漏的,

例如,有一个Activity,Activity包含了一个Fragment,Fragment中有一个LiveData,因此Fragment引用了LiveData。

然后LiveData通过observe方法把Activity当作owner进行了绑定,那么这时候,LiveData的生命周期将和Activity一样。如果这时候因为某种原因,Fragment被销毁了,那么LiveData将不会被销毁,因为它被Activity引用着。LiveData本该回收却无法被回收,那么LiveData就发生内存泄漏了。

源码分析

下面我们进入源码看看LiveData的原理。

observe方法

LiveData是如何监听与其绑定的界面的生命周期的?

这就得从LiveData的与组件的绑定方法开始看了,所以我们来看看LiveData的observe方法。

// LiveData.java;
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    assertMainThread("observe");
    //如果owner的生命周期为DESTROYED,直接return
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        return;
    }
    //将外部传进的observer对象封装成一个LifecycleBoundObserver对象
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    //将observer和wrapper存放到map中
    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);
}

首先,将外部传进的observer对象封装成LifecycleBoundObserver对象,对象名称为wrapper,其实LifecycleBoundObserver就是一个可以监听生命周期的类,我们可以看看LifecycleBoundObserver类的构造方法:

LiveData.LifecycleBoundObserver类:

class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
        @NonNull
        final LifecycleOwner mOwner;

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
            super(observer);
            mOwner = owner;
        }
        
        // …………………………
}

@Deprecated
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
public interface GenericLifecycleObserver extends LifecycleEventObserver { }

public interface LifecycleEventObserver extends LifecycleObserver {
    void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event);
}

首先,我们也可以看到,LifecycleBoundObserver实现了GenericLifecycleObserver这个接口,而实际上,这个接口最终继承自LifecycleObserver这个接口的,

LifecycleObserver是不是有点眼熟?

没错,它是我们在使用lifecycle的时候应该addObserver时需要传递的参数。

所以,我们通过new LifecycleBoundObserver(owner, observer)方法得到的wrapper实际上就是一个LifecycleObserver

在LifecycleBoundObserver类构造方法中,将observer传给其父类使用,而其父类是ObserverWrapper,

我们看看ObserverWrapper的构造方法:

// LiveData.ObserverWrapper类:
private abstract class ObserverWrapper {
    final Observer<? super T> mObserver;
    boolean mActive;
    int mLastVersion = START_VERSION;

    ObserverWrapper(Observer<? super T> observer) {
        mObserver = observer;
    }
    
    // ………………………………
}

可以看到,实际上只是把observer赋值给ObserverWrapper类的mObserver成员变量罢了。

我们继续回到LiveData的observe方法:

// LiveData.java;
private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
            new SafeIterableMap<>();
            
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    assertMainThread("observe");
    //如果owner的生命周期为DESTROYED,直接return
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        return;
    }
    //将外部传进的observer对象封装成一个LifecycleBoundObserver对象
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    //将observer和wrapper存放到mObservers中
    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);
}

mObservers.putIfAbsent(observer, wrapper)这行代码,将observer作为键,wrapper作为值存放到mObservers中,并且会返回一个ObserverWrapper对象。

mObservers是一个由链表实现的支持键值对存储的数据结构,同时,它支持在遍历的过程中删除任意元素,我们可以暂且把它理解为保存observer对象的集合。

如果ObserverWrapper不为null,则observe这个方法会直接return。ObserverWrapper在什么情况不为null呢?

如果观察者observer已经在mObservers这个列表中,并且observer已经有另一个所有者owner,就会不为null。

这是为了防止同一个observer被多个LifecycleOwner绑定,即一个LiveData中的同一个observer只能跟一个LifecycleOwner绑定。否则会抛出“Cannot add the same observer with different lifecycles”的异常。

在observe方法的最后,调用了owner.getLifecycle().addObserver(wrapper)方法,使得wrapper和owner的生命周期进行了绑定。

也就是说,observer此时就可以监听到owner对应的界面的生命周期的变化了!!

setValue方法

那么,setValue方法应该是我们用得最多的LiveData方法了,很明显它是用来更新LiveData的数据的,那么它是怎么实现的呢?我们来看下:

// LiveData.java:
@MainThread
protected void setValue(T value) {
    assertMainThread("setValue");
    mVersion++;
    mData = value;
    dispatchingValue(null);
}

首先看到,setValue方法有个@MainThread注解,说明这个方法只能在主线程中使用,然后在setValue中,将value赋值给mData变量,同时,mVersion变量加1,

mVersion就是数据的版本,说白了就是用来标记数据是否变化的,后面我们还会见到,这里先略过。

方法最后,调用了dispatchingValue(null)方法,我们进入该方法:

// LiveData.java:
void dispatchingValue(@Nullable ObserverWrapper initiator) {
    if (mDispatchingValue) {
        mDispatchInvalidated = true;
        return;
    }
    mDispatchingValue = true;
    do {
        mDispatchInvalidated = false;
        if (initiator != null) {
            considerNotify(initiator);
            initiator = null;
        } else {
            for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
    } while (mDispatchInvalidated);
    mDispatchingValue = false;
}

可以看到,dispatchingValue方法中,有个while循环,在while循环里面,由于initiator为null,所有走else分支的代码,这里又有个for循环,这个for循环是用来遍历

mObservers中的observer对象的,

然后通过considerNotify方法将遍历到的observer对象进行处理

我们看看considerNotify方法:

// LiveData.java:
private void considerNotify(ObserverWrapper observer) {
    //observer对象不处于活跃状态,直接return
    if (!observer.mActive) {
        return;
    }
  
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;
    //noinspection unchecked
    observer.mObserver.onChanged((T) mData);
}

可以看到,首先做了一个判断,外部传入的observer对象是否处于活跃状态,不处于活跃状态,则直接return这个方法。从这里就可看出,

即使数据更新了,但如果界面不处于活跃状态,也不会对数据更新做响应。

然后往下看,我又看到了mVersion这个变量,以及一个mLastVersion变量,

判断observer.mLastVersion这个变量如果小于mVersion,会把mVersion的值赋值给observer.mLastVersion变量,

这种情况就说明数据是新的数据,就可以执行observer的onChanged方法把mData回调出去了。

postValue方法

我们先来看postValue方法。

// LiveData.java:
protected void postValue(T value) {
    boolean postTask;
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        mPendingData = value;
    }
    if (!postTask) {
        return;
    }
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}

postValue方法中,外部传进来的value会赋值给mPendingData,方法的最后会调用postToMainThread方法,postToMainThread,看这个方法的命名应该也能看出来一些东西,就是将这个runnable发布到主线程处理,我们进入postToMainThread详细看看:

// ArchTaskExecutor.java:
@Override
public void postToMainThread(Runnable runnable) {
    mDelegate.postToMainThread(runnable);
}

它通过调用mDelegate的postToMainThread方法,mDelegate实际上就是DefaultTaskExecutor这个类,那么我们再进入这个类的postToMainThread看看:

DefaultTaskExecutor.java:
@Override
public void postToMainThread(Runnable runnable) {
    if (mMainHandler == null) {
        synchronized (mLock) {
            if (mMainHandler == null) {
                mMainHandler = new Handler(Looper.getMainLooper());
            }
        }
    }
    //noinspection ConstantConditions
    mMainHandler.post(runnable);
}

在这个方法中,先判断mMainHandler对象是否为null,如果为null,就创建一个,注意,它是通过Looper.getMainLooper()参数来创建的,说明这个这个mMainHandler就是主线程的handler对象。

最后调用mMainHandler.post(runnable)方法,将runnable对象交给主线程的handler来处理。

那么runnable执行了什么东西呢?

我们回到postValue方法,发现runnable就是mPostValueRunnable,我们看mPostValueRunnable是怎么定义的:

// LiveData.java:
private final Runnable mPostValueRunnable = new Runnable() {
    @SuppressWarnings("unchecked")
    @Override
    public void run() {
        Object newValue;
        synchronized (mDataLock) {
            newValue = mPendingData;
            mPendingData = NOT_SET;
        }
        setValue((T) newValue);
    }
};

我们看到它的run方法,先定义了个newValue变量,然后加锁对newValue赋值为mPendingData变量,mPendingData是在postValue方法内第三行赋值的,前面已经看到过了,然后将mPendingData置为NOT_SET。最后调用setValue方法。

所以,postValue方法实际上就是将线程切到主线程去处理setValue方法。

LiveData对生命周期的响应

举个例子:

有一个界面对一个LiveData对象进行了监听,当界面处于非活跃状态时,如果我们更新了LiveData的数据,那么界面并不会马上响应LiveData的变化(因为界面处于非活跃状态嘛)。当界面重新回到活跃状态时,刚刚更新的LiveData数据会马上进行响应。

为什么界面重新回到活跃状态时(比如activity从onPause状态回到onResume状态),刚刚更新的LiveData数据会马上进行响应呢?

前面已经介绍过,在LiveData的observe方法中,通过owner.getLifecycle().addObserver(wrapper)方法,会使得wrapper和owner的生命周期进行了绑定,

也就是说,owner生命周期变化,wrapper就能在onStateChanged这个方法中监听到。

假设owner是个Activity,那么当Activity处于非活跃状态时,对LiveData进行了setValue操作,则在considerNotify方法的开头会直接被return,也就走不到observer.mObserver.onChanged方法了,也就不能接收到LiveData的数据变化。

当Activity回到活跃状态,wrapper(即LifecycleBoundObserver)的onStateChanged方法就会被回调:

// LiveData.LifecycleBoundObserver类:
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
    if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
        removeObserver(mObserver);
        return;
    }
    activeStateChanged(shouldBeActive());
}

如果Activity处于活跃状态时,就会执行到onStateChanged中的activeStateChanged方法:

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();
    }
    //如果处理活跃状态,就执行dispatchingValue(this)方法
    if (mActive) {
        dispatchingValue(this);
    }
}

首先可以看到,mActive在这里被赋值。然后看到最后三行,判断如果处于活跃状态,就执行dispatchingValue(this)方法,那么这时又回到了setValue的那个流程中,也就是说,Activity生命周期变成活跃状态后,又能触发LiveData的值的更新了。

LiveData的自动解绑

我们知道,LiveData能大大降低内存泄漏出现的可能,原因就是因为它能够自动跟它绑定的组件进行解绑,那么这是怎么做到的呢?还是看到LifecycleBoundObserver这个内部类:

LiveData.java:
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
        @NonNull
        final LifecycleOwner mOwner;

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
            super(observer);
            mOwner = owner;
        }

        @Override
        public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            activeStateChanged(shouldBeActive());
        }

        @Override
        boolean isAttachedTo(LifecycleOwner owner) {
            return mOwner == owner;
        }

        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }
}

onStateChanged方法中,如果监听到owner生命处于DESTROYED时,会执行LiveData类中的removeObserver方法,它的实现如下:

@MainThread
public void removeObserver(@NonNull final Observer<? super T> observer) {
    assertMainThread("removeObserver");
    ObserverWrapper removed = mObservers.remove(observer);
    if (removed == null) {
        return;
    }
    //执行LifecycleBoundObserver的detachObserver方法
    removed.detachObserver();
    //执行ObserverWrapper的activeStateChanged方法
    removed.activeStateChanged(false);
}

removeObserver方法的主要流程分三个步骤:

1、首先从mObservers集合中移除当前的observer对象

2、执行removed.detachObserver(),这行代码实际上会执行LifecycleBoundObserver的detachObserver方法,这里是真正将mOwner与mObserver解绑的地方

3、执行removed.activeStateChanged(false),这行代码实际上会执行ObserverWrapper的activeStateChanged方法,并把false传入,这个方法前面已经看过了,就不详细讲了

LiveData的mData

这里简单的介前面已经介绍过,在setValue方法中,value会赋值给LiveData的mData这个成员变量,我们我看看这个mData。

private volatile Object mData = NOT_SET;

可以看到,它是被volatile修饰的,对java并发有一定了解应该都知道,volatile是用来保证变量的可见性的,防止并发的情况下,多个线程对同一个变量进行修改,出现数据数据不一致的问题。

假设有一个场景,我想用两个线程对一个公共变量x进行加1操作(x的初始值是0),我希望得到的结果是x等于2。

其实,大多数情况下,是能正常得到2这个值的,但是!。

有种情况,线程1和线程2同时从主内存中拿到了x,并把x拷贝到自己的工作内存进行操作,两个线程都对x这个值进行了加1操作,则在这两个线程的工作内存中,x的值都变成了1,

对值进行操作完毕后,然后线程1和线程2就把x的值写回到主内存中,那么此时主内存中的x的值必然是1。

所以在这种情况,数据就不是我想要的了,那么怎样保证这个值一定是2呢?那就是使用volatile了。

由此我们也看出。LiveData中的mData是线程安全的。

LiveData跨组件通信

我们已经知道LiveData可以及时通知组件数据发生变化,还能自动解除绑定,但是LiveData的用途还不止这些。

不知道大家有没有用过EventBus,这个东西可以代替Android传统的Intent、Handler、Broadcast或接口回调,在Fragment、Activity、Service线程之间传递数据,执行方法。EventBus最大的特点就是简洁、解耦,它的框架思想就是消息的发布和订阅,它通过解耦发布者和订阅者简化Android事件传递。

其实,通过LiveData,我们也能实现类似于EventBus的框架,并且使用后不需要手动解除绑定,更加方便和优雅。那么,怎么实现呢?

跨组件通信初探

首先能想到,可以将一个LiveData设置为static的,这样不同的Activity或Fragment就都能访问这个变量,那么监听这个变量值变化也不成问题。这个方法确实能实现LiveData跨Activity/Fragment通信。

举个例子:假设有两个界面,分别是Activity1和Activity2,Activity1通过LiveData发送数据,然后在Activity2中接受数据。

那么我们可以新建一个MyStaticLiveData类,用来保存公共的LiveData:

class MyStaticLiveData {
    companion object {
        val liveData = MutableLiveData<String>()
    }
}

然后Activity1中发送数据,并且有个button用来跳转到Activity2:

class Activity1 : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_live_data)

        MyStaticLiveData.liveData.value = "data from LiveDataActivity."
    }

    fun toLiveData2Activity(view: View) {
        startActivity(Intent(this, Activity2::class.java))
    }
}

Activity2中,将公共的LiveData和Activity2进行绑定监听,这样就能接受到Activity1发送过来的数据了,并且我们也不需要在onDestroy中解绑LiveData,因为它会自动解绑。

class Activity2 : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_live_data2)

        MyStaticLiveData.liveData.observe(this, {
            tv2.text = it
        })
    }
}

这样看来,确实实现了EventBus粘性事件的功能,并且用法更加简洁。

但是它的缺点也是很明显的,它不够优雅,而且,每当我想搞个新的LiveData的时候,都需要在MyStaticLiveData中手动创建,另外,没有一个东西统一来管理这些LiveData,并且,每个LiveData都是static的,所以,开发中不建议这么写,这里只做演示用,不建议用到实际开发场景中 !!!。

另外,在开发过程中,粘性事件大部分情况下我们都是不需要用到的。而更多的场景是,我们希望监听者能在注册监听后才开始接收发送过来的消息,在注册前发送的消息一律不接收

数据倒灌

我们刚刚演示的例子,业内有另一种更常见的叫法,数据倒灌。

一句话概括就是,先给LiveData设置了value,然后监听者才开始对LiveData进行监听,这时LiveData的value会立马回调给监听者。

产生数据倒灌的原因

这还得从源码的角度进行分析,我们先看setValue方法:

// LiveData.java:
......................................
static final int START_VERSION = -1;
private int mVersion = START_VERSION;
......................................
@MainThread
protected void setValue(T value) {
    assertMainThread("setValue");
    mVersion++;
    mData = value;
    dispatchingValue(null);
}

注意这里的mVersion,在setValue中进行了自增操作。另外,mVersion的值默认为-1。所以当我们第一次调用setValue时,LiveData中的mVersion的值等于0

当调用LiveData进行observe时,我们在上面的源码也分析过,observe最终会走到considerNotify方法:

// LiveData.java:
private void considerNotify(ObserverWrapper observer) {
    ......................................
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;
    observer.mObserver.onChanged((T) mData);
}

private abstract class ObserverWrapper {
......................................
    int mLastVersion = START_VERSION;
......................................
}

可以看到,当observermLastVersion小于mVersion时就会把之前的数据回调给监听者。另外,observer中的mLastVersion默认值也为-1,所以在considerNotify中,很明显,mLastVersion小于mVersion(-1 < 0),所以会执行onChanged方法把数据回调给监听者

如何解决数据倒灌

目前解决方案有非常多,这里只说一种,那就是通过反射干预Version值的方式。根据之前的分析,只需要在LiveData绑定owner的时候把Wrapper的version设置成跟LiveData的version一致即可。那么怎么实现,推荐大家去看下美团大佬写的文章,一定会收获很大:

https://www.cnblogs.com/meituantech/p/9376449.html

这里面有非常详细的分析过程已经实现过程。本章篇幅有限,就不详细跟大家探讨了。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一场雪ycx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值