LiveData

1、简单使用

class MainActivity : AppCompatActivity() {

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

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        liveData.value = "你好-test"
    }

    fun toTest(view: View) {
        startActivity(Intent(this, TestActivity::class.java))
    }
}
class TestActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test)
        MainActivity.liveData.observe(this, Observer {
            Toast.makeText(this, it, Toast.LENGTH_LONG).show()
        })
    }
}

在MainActivity中有一个liveData,在onOncreate()时赋值为“你好-test”,可以点击按钮跳转到TestActivity。在TestActivity中,监听了liveData的数据变化。

1.1 作用

LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity/Fragment)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。

  1. LiveData是一个数据持有者,给源数据包装一层
  2. 源数据使用LiveData包装后,可以被observer观察,数据有更新时observer可感知。
  3. 但 observer的感知,只发生在(Activity/Fragment)活跃生命周期状态(STARTED、RESUMED)。

LiveData使得数据的更新能以观察者模式被observer感知,且此感知只发生在 LifecycleOwner的活跃生命周期状态。

1.2 特点

  • 确保界面符合数据状态,当生命周期状态变化时,LiveData通知Observer,可以在observer中更新界面。观察者可以在生命周期状态更改时刷新界面,而不是在每次数据变化时刷新界面。
  • 不会发生内存泄漏,observer会在LifecycleOwner状态变为DESTROYED后自动remove。
  • 不会因 Activity 停止而导致崩溃,如果LifecycleOwner生命周期处于非活跃状态,则它不会接收任何 LiveData事件。
  • 不需要手动解除观察,开发者不需要在onPause或onDestroy方法中解除对LiveData的观察,因为LiveData能感知生命周期状态变化,所以会自动管理所有这些操作。
  • 数据始终保持最新状态,数据更新时 若LifecycleOwner为非活跃状态,那么会在变为活跃时接收最新数据。例如,曾经在后台的 Activity 会在返回前台后,observer立即接收最新的数据。

2、先看看liveData添加监听的过程

    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        // 只能在主线程进行
        assertMainThread("observe");
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore 添加监听的owner处于destroy状态不处理
            return;
        }
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer); //1
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper); //2
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        //wrapper添加对生命周期变化的监听
        owner.getLifecycle().addObserver(wrapper); //3
    }

上面代码的第一处注释就是把生命周期的所有者(activity)和我们传递的观察者参数,合并为一个对象LifecycleBoundObserver,也就是生命周期绑定观察者。

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

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

        @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

        // activity生命周期改变回调
        @Override
        public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            activeStateChanged(shouldBeActive());
        }
        ···
    }

LifecycleBoundObserver继承了ObserverWrapper和实现了LifecycleEventObserver,在生命周期改变的时候也分发值的改变。
第二处注释mObservers是一个LinkedList,他不是线程安全的。观察者和LifecycleBoundObserver分别作为key和value放入mObservers,存在value的话就直接返回。并且同一个observer不能添加不同的owner(activity)
第三处注释就是LifecycleBoundObserver实现对activity生命周期改变的监听。

添加观察者时序图:
liveData添加观察者.png

3、数据改变的分发

在测试代码中,我们先是设置了liveData的值,在TestActivity中才对liveData进行观察。而实际上在打开TestActivity时就会弹出你好-test的Toast
通过添加观察者的过程可以知道,在activity生命周期改变的时候会调用LifecycleBoundObserver的onStateChanged()

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

如果当前状态处于destroy移除观察者,并把当前是否处于活跃状态传递给activeStateChanged()

//ObserverWrapper#activeStateChanged(boolean newActive)
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);
    }
}

分发值的改变

//LiveData
void dispatchingValue(@Nullable ObserverWrapper initiator) {
    if (mDispatchingValue) {
        mDispatchInvalidated = true;
        return;
    }
    mDispatchingValue = true;
    do {
        mDispatchInvalidated = false;
        if (initiator != null) {// 生命周期改变的回调
            considerNotify(initiator);
            initiator = null;
        } else {// setValue()的调用
            for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
    } while (mDispatchInvalidated);
    mDispatchingValue = false;
}

通知

private void considerNotify(ObserverWrapper observer) {
    if (!observer.mActive) {
        return;
    }
  
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    if (observer.mLastVersion >= mVersion) {//1
        return;
    }
    observer.mLastVersion = mVersion;
    //noinspection unchecked
    //2
    observer.mObserver.onChanged((T) mData);
}

在注释1处,判断livedata中的version是否小于ObserverWrapper中的version。在注释2处通知了observer值的改变。看看setValue()中的操作。

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

setValue时mVersion++并且给mData赋值。在测试代码中是在TestActivity中添加的观察者dispatchingValue(null);没有观察者响应。
这就可以解释为什么,后添加的观察者可以收到上一个的数据变化。是因为在setVaule时version进行了加1,并把设置的数据赋值给了我mData,在添加观察时注册了生命周期的监听,在活跃状态时调用了considerNotify的方法。在其中判断mLastVersion不大于mVersion说明观察还没得到数据变化的回调,或者不是最新的变化。


通知数据变化时序图.png

liveData类图
LiveData类图.png

3、扩展使用

  1. 自定义LiveData,本身回调方法覆写:onActive()、onInactive()。
  2. 实现LiveData为单例模式,便于在多个Activity、Fragment之间共享数据。

官方例子:

public class StockLiveData extends LiveData<BigDecimal> {
        private static StockLiveData sInstance; //单实例
        private StockManager stockManager;

        private SimplePriceListener listener = new SimplePriceListener() {
            @Override
            public void onPriceChanged(BigDecimal price) {
                setValue(price);//监听到股价变化 使用setValue(price) 告知所有活跃观察者
            }
        };

     //获取单例
        @MainThread
        public static StockLiveData get(String symbol) {
            if (sInstance == null) {
                sInstance = new StockLiveData(symbol);
            }
            return sInstance;
        }

        private StockLiveData(String symbol) {
            stockManager = new StockManager(symbol);
        }

        //活跃的观察者(LifecycleOwner)数量从 0 变为 1 时调用
        @Override
        protected void onActive() {
            stockManager.requestPriceUpdates(listener);//开始观察股价更新
        }

        //活跃的观察者(LifecycleOwner)数量从 1 变为 0 时调用。这不代表没有观察者了,可能是全都不活跃了。可以使用hasObservers()检查是否有观察者。
        @Override
        protected void onInactive() {
            stockManager.removeUpdates(listener);//移除股价更新的观察
        }
    }

4、高级用法

4.1 数据修改 - Transformations.map

    //数据修改
    val liveData1 = MutableLiveData<String>()
    val map = Transformations.map(
        liveData1
    ) {
        it + "zhangsan"
    }
    map.observe(this) {
    }

4.2 数据切换 - Transformations.switchMap

如果想要根据某个值 切换观察不同LiveData数据,则可以使用Transformations.switchMap()方法

    //数据切换
    val liveData2 = MutableLiveData<String>()
    val liveData3 = MutableLiveData<String>()
    //切换条件
    val liveDataSwitch = MutableLiveData<Boolean>(
    val switchMap = Transformations.switchMap(
        liveDataSwitch
    ) { input ->
        if (input == true) {
            liveData2
        } else {
            liveData3
        }
    }
    switchMap.observe(this) {
        Log.e("livedatademo", it)
    }
    liveDataSwitch.value = true
    liveData2.value = "lisi"
    liveData3.value = "王五"
Transactions.map.png

4.3 观察多个数据 - MediatorLiveData

MediatorLiveData 是 LiveData 的子类,允许合并多个 LiveData 源。只要任何原始的 LiveData 源对象发生更改,就会触发 MediatorLiveData 对象的观察者。

    //观察多个数据
    val mediatorLiveData = MediatorLiveData<String>()
    val liveData4 = MutableLiveData<String>()
    val liveData5 = MutableLiveData<String>()
    mediatorLiveData.addSource(liveData4) {
        Log.e("livedatademo", "liveData4:$it")
        mediatorLiveData.value = it
    }
    mediatorLiveData.addSource(liveData5) {
        Log.e("livedatademo", "liveData5:$it")
        mediatorLiveData.value = it
    }
    mediatorLiveData.observe(this) {
        Log.e("livedatademo", "mediatorLiveData:$it")
    }
    liveData5.value = "ktx"
MediatorLiveData.png

5、Transformations原理

map和switchMap的原理差不多,先看看map是如何修改数据的。

    @MainThread
    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;
    }

现时创建了一个MediatorLiveData,MediatorLiveData是MutableLiveData的子类,看看addSource方法

    @MainThread
    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();
        }
    }

如果MediatorLiveData有活跃观察者,就调用plug():

    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是MediatorLiveData的内部类,是对源LiveData的包装。plug()中让源LiveData调用observeForever方法添加观察者观察自己。 这里为啥使用observeForever方法呢,这是因为源LiveData在外部使用时不会调用observer方法添加观察者,这里永远观察是为了在源LiveData数据变化时及时回调到 mObserver.onChanged(v)方法,也就是Transformations map方法中的nChanged方法。 而在e.plug()前是有判断 MediatorLiveData 确认有活跃观察者的。
最后map方法中的nChanged方法中有调用MediatorLiveData实例的setValue(mapFunction.apply(x)); 并返回实例。而mapFunction.apply()就是map方法传入的修改逻辑Function实例。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,284评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,115评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,614评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,671评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,699评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,562评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,309评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,223评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,668评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,859评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,981评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,705评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,310评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,904评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,023评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,146评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,933评论 2 355

推荐阅读更多精彩内容