Jetpack 源码分析(二) - LiveData源码分析

  距离上一篇文章差不多有一个月,感觉进度有点慢。唉,在这一个月里面,自己有点颓废啊!这篇文章居然拖了这么久。废话少说,今天我们就来学习一下Jetpack中的LiveData,研究一下它的原理。
  本文参考资料:

  1. LiveData 概览
  2. ViewModels and LiveData: Patterns + AntiPatterns
  3. LiveData beyond the ViewModel — Reactive patterns using Transformations and MediatorLiveData
  4. LiveData with SnackBar, Navigation and other events (the SingleLiveEvent case)
  5. How and where to use Transformations.switchMap?

  注意,本文LiveData的所有源码均来自于2.0.0版本

1. 概述

  在正式分析LiveData之前,我们先来了解一下LiveData是一个什么东西吧(虽然大家可能都知道),不过我还是多说几句。
  从官方文档的介绍来看的话,LiveData是一个可观察的数据存储器类。但是与普通可观察类不同的是,LiveData是能感知组件(Activity 、Fragment或者Service等)的生命周期。正因为拥有这个感知能力,使得LiveData在组件Destroy时能自动移除观察者对象,这样便能避免很多NPE和内存泄漏的问题。
  LiveData的优点还有很多,这里就不过多的介绍,有兴趣的同学可以看看官方文档:LiveData 概览,官方文档介绍的非常详细。
  本文从LiveData的基本使用开始,由浅入深的介绍LiveData的方方面面。同时由于本系列文章还未介绍ViewModel,所以本文LiveData的所有例子都在放在Activity中,但是按照官方推荐,LiveData和ViewModel结合使用,希望大家不要被我的例子误导。
  本文打算从如下几个方面来介绍LiveData:

  1. LiveData的基本使用。
  2. LiveDdata的原理分析,其中会着重分析几个点:1. Version的控制,LiveData是怎么知道哪些Observer需要通知,哪些Observer不需要通知;2. LiveData是怎么实现只在活跃状态下才会通知Observer,同时又是如何实现从非活跃状态变为活跃状态会通知Observer;3. LiveData是怎么实现在组件Destroy时自动移除所有的Observer;4. onActive方法和onInactive方法的作用和回调时机。
  3. MediatorLiveData的基本使用和实现原理、以及怎么merge多个LiveData的数据。
  4. Transformationsmap方法和switchMap方法的区别和实现原理。

1. LiveData 的基本使用

  首先,我们先来看看LiveData是怎么使用的:

class LiveDataDemoActivity : AppCompatActivity() {

    private lateinit var mTextView: TextView
    private lateinit var mButton: Button
    private val mTextLiveData: MutableLiveData<String> = MutableLiveData()
    private var mUpdateCount = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_live_data_demo)
        mTextView = findViewById(R.id.textView)
        mButton = findViewById(R.id.button)
        mTextLiveData.observe(this, Observer {
            mTextView.text = it
        })
        mButton.setOnClickListener {
            mTextLiveData.value = "update content ${mUpdateCount++}"
        }
    }
}

  上面的例子展示了一个简单的效果,当我们点击Button时,更新TextView显示的内容。相比较于以前的例子,我们这个例子不会直接操作TextView来实现更新的,而是更新LiveData,间接的更新了TextView显示的内容。可能有人在想,这不是多此一举吗?
  答案当然是否定的,这样做有一个很多的好处,就是实现了View层和Model层的解耦。这样来想,如果Model层很多地方都需要更新TextView的内容,岂不是都要持有TextView的引用吗?而有了LiveData之后,只需要持有LiveData对象即可。这样就不会导致内存泄漏和空指针异常。简而言之,LiveData就是数据驱动,数据更新了,对应的UI也跟着更新。
  切记,真实开发不应该把LiveData直接放在View层。它应该放在Model层,用来连接View层和Mode层。
  同时,我们可以从上面的例子中发现一个小细节,我们并没有在Activity的onDestroy方法里面去remove它的Observer。这是因为,LiveData它会自己监听组件的生命周期,当组件Destroy时,会自动remove Observer,从而避免空指针异常。
  如上便是LiveData的基本使用,是不是很简单的?确实比较简单,我们还有很多扩展使用没有介绍,这些都会在后面的内容中介绍。

2. LiveData的原理分析

  我们已经了解了LiveData的基本使用,至此我们就来分析它的源码。我们先来看看几个方法:

方法名 解释
observe observe是LiveData非常重要的一个方法,作用是给LiveData添加一个
观察者对象(Observer)。这个方法两个参数,其中第一个参数是
LifecycleOwner对象,表示LiveData需要感知它的生命周期。
observeForever 与observe方法相同作用还有一个observeForever方法。该方法跟
observe方法有一个很大的区别就是,通过该方法不需要感知组
件的生命周期,也就是无论在何时更新了数据,通过该方法添加
的Observer都会被通知到。使用该方法需要注意的是:必须在适
当的时机中调用removeObserver方法,用来remove对应的Observer。

(1). observe方法

  我们先来看看observe方法的源码:

    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        assertMainThread("observe");
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        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);
    }

  observe方法只要分为如下几步:

  1. check 组件的生命中周期。如果组件的生命已经处于Destroy状态,没有必要再添加Observer。
  2. 将传递进来的两个参数包装成一个LifecycleBoundObserver对象,同时检查该Observer是否已经添加到其他组件里面,如果已经添加, 则会抛出IllegalArgumentException
  3. LifecycleOwner添加一个Lifecycle的观察者对象(即LifecycleBoundObserver 对象)。从这里,我们可以看出来,LifecycleBoundObserver的本质就是一个LifecycleObserver

(2). observeForever方法

  看完了observe方法的实现,我们再来看看observeForever:

    @MainThread
    public void observeForever(@NonNull Observer<? super T> observer) {
        assertMainThread("observeForever");
        AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing != null && existing instanceof LiveData.LifecycleBoundObserver) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        wrapper.activeStateChanged(true);
    }

  跟observe方法相比,observeForever方法主要有两个区别:

  1. 使用AlwaysActiveObserver来监听生命周期。同时从AlwaysActiveObserver 的实现中,我们可以看出来,shouldBeActive方法永远为true,表示说是AlwaysActiveObserver永远能够接受到通知的。
  2. 直接调用了activeStateChanged用来更新状态,并且尝试着通知Observer。而observe方法是通过监听生命周期进而间接的回调activeStateChanged方法。

(3).ObserverWrapper和LifecycleBoundObserver

  在正式了解LifecycleBoundObserver之前,我们先来看看它的uml类图吧。


  在我们了解了Lifecycle之后,我们知道生命周期的回调是在onStateChanged方法里面。所以,我们来看看LifecycleBoundObserveronStateChanged方法的实现:

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

  从上面的代码中,我们可以得到一个信息,就是当组件(Activity、Fragment等)Destroy时,LiveData会自动移除对应的Observer,这恰好与我们前面所说的内容与之呼应。其次,我们会发现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();
            }
            if (mActive) {
                dispatchingValue(this);
            }
        }

  activeStateChanged方法主要分为如下几步:

  1. 如果状态就是最新状态,那么表示更新通知过所有的Observer,没必要再通知了。比如说,在Activity的onStart和onResume的两个生命周期里面,都会回调activeStateChanged方法,并且newActive都为true,当我们已经在onStart通知过了,在onResume时就没必要再通知了。
  2. 更新LiveData的mActiveCount,mActiveCount表示的就是LiveData活跃的Observer。如果LiveData活跃的Observer为0,同时该Observer将更新为活跃状态,那么就会回调LiveData的onActive方法;反之,如果该Observer变为非活跃状态,同时mmActiveCount为0,则回调onInActive方法。
  3. 如果该Observer更新到活跃状态,会调用dispatchingValue方法,去尝试通知每个Observer更新数据。

  我们来看看dispatchingValue方法:

    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方法中,我们需要如下2点:

  1. initiator为null和不为null的区别。其中initiator为null,则会遍历所有的Observer,然后尝试所有的Observer;initiator不为null,则只会通知initiator对象中持有的Observer。这种情况,我们可以简单的理解为局部通知和全局通知。那么什么时候为null,什么时候不为null。纵观整个LiveData的源码,当我们通过setValue和postValue方法更新LiveData持有的数据时,此时initiator为null,则会通知所有的Observer;当时Observer新添加到LiveData中来,或者Activity和Fragment生命周期变化了,此时initiator不为null,此时就是ObserverWrapper 通知自己内部持有的Observer。
  2. mDispatchingValuemDispatchInvalidated这两个变量设计的非常巧妙。当第一个ObserverWrapper 调用dispatchingValue方法时,此时mDispatchingValue将设置为true,mDispatchInvalidated会未设置为false。如果第一个ObserverWrapper 还未执行完dispatchingValue方法,第二个ObserverWrapper因为部分原因(比如数据更新了或者生命周期变换了)也来调用dispatchingValue,此时它会将第一个ObserverWrapper的调用全部失效,即mDispatchInvalidated设置为true,然后让第一个ObserverWrapper 重新遍历通知所有的Observer。这样能保证每个Observer能收到最新的通知,接受到最新的数据。

  我们知道,在dispatchingValue方法中并没有真正的Observer回调方法。真正回调Observer的方法的地方是在considerNotify方法里面。我们来看看:

    private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }
        // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
        //
        // we still first check observer.active to keep it as the entrance for events. So even if
        // the observer moved to an active state, if we've not received that event, we better not
        // notify for a more predictable notification order.
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        //noinspection unchecked
        observer.mObserver.onChanged((T) mData);
    }

  considerNotify方法主要分为如下几步:

  1. 判断ObserverWrapper 是否活跃状态,如果不是活跃状态,则不用通知更新。
  2. 判断当前组件是否处于活跃状态,如果不是活跃状态,则调用activeStateChanged方法,将当前ObserverWrapper设置为非活跃状态。可能有人有疑问,前面我们已经判断是否活跃,为啥在这里还要判断组件是否为活跃状态,这俩不是同步的吗?从Google爸爸的注释来看,可能存在组件已经更新了状态,但是我们还没有收到对应的Event来更新ObserverWrapper的状态。至于具体是什么情形呢?官方也没有给出准确的答案,对此我也有疑问。
  3. 判断当前ObserverWrapper的Version,如果当前的Version大于等于LiveData本身的版本,表示当前ObserverWrapper已经通知更新了,不需要再通知。
  4. 调用Observer的onChanged方法。在这里,我们终于看到了真正的回调。

  对于onChanged方法回调的路径真是不容易,由于过程比较繁琐,我在这里简单的总结。

onChanged方法调用路径主要分为两条:

  1. LifecycleBoundObserver # onStateChanged -> LifecycleBoundObserver # activeStateChanged -> LiveData # dispatchingValue -> LiveData # considerNotify。此条路径主要处理的case是组件生命周期的变化。其中activeStateChanged方法保证了只有处于活跃状态Observer才会收到通知;dispatchingValue方法保证此条路径自己一个Observer收到通知;considerNotify方法再次保证处于活跃的Observer才会通知,同时还保证了一个Observer对于同一次更新收到一次通知(使用Version控制的)。
  2. LiveData # setValue -> LiveData # dispatchingValue -> LiveData # considerNotify 。此条路径处理的case是外部条件更新LiveData持有的数据。其他地方跟路径1类似,唯一区别就是在considerNotify会通知所有的Observer。

3. MediatorLiveData的基本使用和原理分析

  说完了最基本的LiveData,我们再来看看它的一个子类--MediatorLiveData。用我们上面的那个例子,假设TextView显示的内容不是被一个LiveData控制的,而是多个,比如说10个,我们应该怎么实现呢?有一个简单的方法就是定义10个LiveData,同时监听这10个LiveData的变化。
  对于这种方法的好与坏我不置可否,但是有一点,我需要提出来。我们都知道,LiveData是被定义ViewModel,View层从VIewModel里面获取LiveData从而监听。像上面的解决方法,我们就要从ViewModel获取这10个LiveData,想一想这代码会写成什么样子?那么有没有一种办法能帮助获取一个LiveData对象就能监听这个10个LiveData的变化,那当然就要让MediatorLiveData出手了。

(1). MediatorLiveData的基本使用

  MediatorLiveData的作用就是合并多个LiveData源,我们先来看看它是怎么使用的吧。

class MediatorLiveDataDemoActivity : AppCompatActivity() {

    private lateinit var mTextView: TextView
    private lateinit var mButton: Button
    private val mTextLiveData: MutableLiveData<String> = MutableLiveData()
    private val mText2LiveData: MutableLiveData<String> = MutableLiveData()
    private val mMergeTextLiveData: MediatorLiveData<String> = MediatorLiveData();
    private var mUpdateCount = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_mediator_live_data_demo)
        mTextView = findViewById(R.id.textView)
        mButton = findViewById(R.id.button)
        mButton.setOnClickListener {
            if (mUpdateCount % 2 == 0) {
                mTextLiveData.value = "update content ${mUpdateCount++}"
            } else {
                mText2LiveData.value = "update content ${mUpdateCount++}"
            }
        }
    }

    private fun observeV1() {
        mTextLiveData.observe(this, Observer {
            mTextView.text = it
        })
        mText2LiveData.observe(this, Observer {
            mTextView.text = it
        })
    }

    private fun observeV2() {
        val observer = Observer<String> {
            mMergeTextLiveData.value = it;
        }
        mMergeTextLiveData.addSource(mTextLiveData, observer)
        mMergeTextLiveData.addSource(mText2LiveData, observer)
        mMergeTextLiveData.observe(this, Observer {
            mTextView.text = it
        })
    }
}

  这里我将普通实现方案(即observeV1方法)和MediatorLiveData实现方案(即observeV2方法)。从具体实现的代码,虽然V2的代码比V1的多,但是V2更加收敛,我们只要知道mMergeTextLiveData的存在即可,不需要管TextView的内容具体由几个LiveData控制的。

(2). MediatorLiveData的原理

  从本质来看,MediatorLiveData就是一个LiveData,所以LiveData有的特点,MediatorLiveData都有。那么,我们直接来看一下,MediatorLiveData独有的特点,就是能够合并多个LiveData源,我们去瞧瞧是怎么实现的。
  我们直接从addSource方法入手,看看其内部的实现:

    public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
        Source<S> e = new Source<>(source, onChanged);
        Source<?> existing = mSources.putIfAbsent(source, e);
        if (existing != null && existing.mObserver != onChanged) {
            throw new IllegalArgumentException(
                    "This source was already added with the different observer");
        }
        if (existing != null) {
            return;
        }
        if (hasActiveObservers()) {
            e.plug();
        }
    }

  addSource方法内部做的事情非常的少,总结起来就是分为两步:

  1. 将传递进来的LiveData和对应的Observer包装成一个Source对象。
  2. 如果此时MediatorLiveData已经有活跃的Observer,就表示此时对应的组件已经处于活跃状态了,那么就是调用plug方法。

  我们从addSource方法看不出来有啥特殊的地方,我们要想知道MediatorLiveData是怎么同时监听多个LiveData,必须从Source下手。

    private static class Source<V> implements Observer<V> {
        final LiveData<V> mLiveData;
        final Observer<? super V> mObserver;
        int mVersion = START_VERSION;

        Source(LiveData<V> liveData, final Observer<? super V> observer) {
            mLiveData = liveData;
            mObserver = observer;
        }

        void plug() {
            mLiveData.observeForever(this);
        }

        void unplug() {
            mLiveData.removeObserver(this);
        }

        @Override
        public void onChanged(@Nullable V v) {
            if (mVersion != mLiveData.getVersion()) {
                mVersion = mLiveData.getVersion();
                mObserver.onChanged(v);
            }
        }
    }

  Source的实现非常的简单,内部持有一个LiveData对象和一个Observer对象。同时我们看到的是,在plug方法里面,通过调用LiveData的observeForever方法用来监听LiveData的变化。当LiveData持有的数据发生了变化,会回调Source的onChanged方法,onChanged方法会调用内部持有的Observer的onChanged方法,从而调用到外面我们定义的Observer对象中去。在那里,我们做了一件事--件更新的值设置到MediatorLiveData中去,由于我们监听了MediatorLiveData,所以所有LivaData变化都会经过MediatorLiveData更新到TextView上去。
  从这里,我们可以看出来,MediatorLiveData类似于一个主管道,所有子管道的更新到都会流到这个主管道中去。

(3). 如何使用MediatorLiveDatamerge多个LiveData呢?

  我们知道在RxJava,zip操作符可以将两个数据流合并成一个数据流,再传递到下游去。LiveData中并没有现成的API供我们使用,所以需要自我实现。下面我将贴出一个简单的Demo来展示如何实现的,主要思路来源于:LiveData beyond the ViewModel — Reactive patterns using Transformations and MediatorLiveData

fun <T, A, B> LiveData<A>.mergeOtherLiveData(
    other: LiveData<B>,
    onChanged: (A, B) -> T
): MediatorLiveData<T> {
    val result = MediatorLiveData<T>()
    val mergeInvoker = {
        val selfValue = this.value
        val otherValue = other.value
        if (selfValue != null && otherValue != null) {
            result.value = onChanged(selfValue, otherValue)
        }
    }
    result.addSource(this) {
        mergeInvoker.invoke()
    }
    result.addSource(other) {
        mergeInvoker.invoke()
    }
    return result
}

  这里,我给LiveData定义了一个扩展方法,主要就是通过MediatorLiveData实现的,具体实现也比较简单,这里就不解释。我们来看一下怎么使用的:

class MergeLiveDataActivity : AppCompatActivity() {

    private val mAvatarLiveData: MutableLiveData<Avatar> = MutableLiveData()
    private val mIntroductionLiveData: MutableLiveData<Introduction> = MutableLiveData()
    private lateinit var mUserLiveData: MutableLiveData<User>

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mUserLiveData =
            mAvatarLiveData.mergeOtherLiveData(mIntroductionLiveData) { avatar, introduction ->
                User(avatar, introduction)
            }
    }
}

  在这里,我简单的定义了一个User类。其中User类内部分为两个部分:Avatar和Introduction。我们可以这样来假设,在实际开发中有两个请求分别这两部分的数据,只有等待两个请求回来时,才算是User信息请求完成。所以,这里我们通过mergeOtherLiveData方法来合并两个LiveData的数据。

4. Transformations的map方法和switchMap方法的区别和实现原理

  我们在使用LiveData时,有一个场景应该是非常常见的--类型映射,比如说从A类型映射到B类型。这里我们就需要了解map和switchMap。

(1).map方法

  假设,有一个LiveData<User>对象,我们想要从中获取User的name和age拼接成一个String,这个应该怎么办呢?普通的方法就是给这个对象添加Observer对象,然后在手动拼接处理。这种方法有一个问题就是,如果很多地方都需要这样处理,那岂不是要添加很多的Observer对象。此时,更好的办法就是通过map方法进行简单的转换:

val mUserLiveData:MutableLiveData<User> = MutableLiveData()
val mInfoLiveData:MutableLiveData<String> = map(mUserLiveData) { user->
     MutableLiveData(user.mName + " " + user.age)
}

  上面是我随手写的伪代码,大家先凑合着吧。接下来我们来看一下map方法的实现:

    public static <X, Y> LiveData<Y> map(
            @NonNull LiveData<X> source,
            @NonNull final Function<X, Y> mapFunction) {
        final MediatorLiveData<Y> result = new MediatorLiveData<>();
        result.addSource(source, new Observer<X>() {
            @Override
            public void onChanged(@Nullable X x) {
                result.setValue(mapFunction.apply(x));
            }
        });
        return result;
    }

  map方法最大的特点就是只支持静态转换。什么叫做静态转换,就是要想转换的LiveData对象已经确定,即已经初始化了。如果我们要想动态转换应该怎么办呢?那就是switchMap方法,这也是这两个方法最大的区别。

(2). switchMap方法

  在了解switchMap方法之前,我们先来了解一下什么叫做动态转换吧。假设有两个LiveData,其中一个LiveData持有的userId,我们称之为mUserIdLiveData,一个LiveData持有的User,我们称之为mUserLiveData。当mUserIdLiveData发生了变化,我们想要的结果是mUserLiveData也随之发生变化。
因为User要等请求回来,我们才知道具体的对象,所以此时map方法不适合此情形,那么用switchMap 应该怎么实现的呢?

val mUserIdLiveData = MutableLiveData<String>()
val mUserLiveData = switchMap(mUserIdLiveData){ userId -> 
    repository.loadUserById(userId)
}

  整个过程是如此的:mUserIdLiveData的更新导致了User的更新,如果不通过switchMap方法,mUserLiveData 根本不能知道Id更新。
  接下来,我们再看看switchMap的实现:

    @MainThread
    public static <X, Y> LiveData<Y> switchMap(
            @NonNull LiveData<X> source,
            @NonNull final Function<X, LiveData<Y>> switchMapFunction) {
        final MediatorLiveData<Y> result = new MediatorLiveData<>();
        result.addSource(source, new Observer<X>() {
            LiveData<Y> mSource;

            // (1)
            @Override
            public void onChanged(@Nullable X x) {
                LiveData<Y> newLiveData = switchMapFunction.apply(x);
                if (mSource == newLiveData) {
                    return;
                }
                if (mSource != null) {
                    result.removeSource(mSource);
                }
                mSource = newLiveData;
                if (mSource != null) {
                    result.addSource(mSource, new Observer<Y>() {
                        // (2)
                        @Override
                        public void onChanged(@Nullable Y y) {
                            result.setValue(y);
                        }
                    });
                }
            }
        });
        return result;
    }

  实现也是非常的简单,我结合上面的例子简单的解释一下。当mUserIdLiveData更新,(1)处方法会被调用,此时通过我们传递进去的Callback接口创建一个新的LiveData,然后在这个新的LiveData添加一个观察者,当这个新的LiveData数据请求回来,会回调(2)方法,此时result就被更新。如果我们给这个result对象设置了Observer观察者,我们就能监听到数据的更新。
  不得不说,switchMap方法设计真的太巧妙,短短几行代码就实现了效果。

5. 总结

  到此为止,LiveData相关的介绍和分析也结束了。在这里,我对本文做一个简单的总结。

  1. LiveData通知Observer主要有两个路径:1. 通过setValue或者postValue,此路径对所有活跃的Observer都生效;2. 添加一个新的Observer,如果此时对应的组件处于活跃状态,那么该Observer的onChanged方法也会被回调,但是只有该Observer的onChanged方法被回调,并不会影响到其他Observer。
  2. MediatorLiveData可以merge多个LiveData源。内部是通过一个Source类实现,当某一个LiveData更新了,Source类将对应的更新作用到MediatorLiveData的Observer。
  3. map 和switchMap区别在于:map只支持静态转换,而switchMap同时支持静态转换和动态转换。同时map和switchMap内部都是用MediatorLiveData实现的。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容