Android Jetpack系列--2.LiveData使用及源码解析

LiveData

定义

  • 一种可观察的数据存储器类,直译为实时数据(是一个数据持有者,给源数据包装一层,源数据使用LiveData包装后,可以被observer观察,数据有更新时observer可感知);
  • 具有生命周期感知能力,可确保 LiveData 仅更新处于活跃生命周期状态(STARTED、RESUMED)的应用组件观察者(observer);

特点

  1. 确保界面符合数据状态:当生命周期状态变化时,LiveData通知Observer,可以在observer中更新界面。
    观察者可以在生命周期状态更改时刷新界面,而不是在每次数据变化时刷新界面。
  2. 不会发生内存泄漏: observer会在LifecycleOwner状态变为DESTROYED后自动remove;
  3. 不会因 Activity 停止而导致崩溃:如果LifecycleOwner生命周期处于非活跃状态,则它不会接收任何 LiveData事件;
  4. 不需要手动解除观察:能自动管理生命周期
  5. 数据始终保持最新状态:数据更新时 若LifecycleOwner为非活跃状态,那么会在变为活跃时接收最新数据;

LiveData的简单使用

class LiveDataActivity : AppCompatActivity() {
    private lateinit var mMutableLiveData: MutableLiveData<String>

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

        //1.创建LiveData实例,指定源数据类型
        mMutableLiveData = MutableLiveData<String>()

        //2. 创建Observer实例,实现onChanged()方法,用于接收源数据变化并刷新UI
        val observer = Observer<String> {
            LjyLogUtil.d("mMutableLiveData.observe.onChanged:${it}")
        }

        //3 LiveData实例使用observe()方法添加观察者observer,并传入LifecycleOwner
        mMutableLiveData.observe(this, observer)
        //4 更改LiveData中的数据
        //4.1 如果想要在LiveData对象分发给观察者之前对其中存储的值进行更改,可以使用Transformations.map()
        val mapLiveData = Transformations.map(mMutableLiveData, Function {
            it + "_LJY"
        })
        mapLiveData.observe(this, Observer {
            LjyLogUtil.d("mapLiveData.observe.onChanged:${it}")
        })
        //4.2 Transformations.switchMap(),切换监听
        val liveData0 = MutableLiveData<Boolean>()
        val liveData1 = MutableLiveData<String>()
        val liveData2 = MutableLiveData<String>()
        val switchMapLiveData = Transformations.switchMap(liveData0, Function {
            if (it) {
                liveData1
            } else {
                liveData2
            }
        })
        switchMapLiveData.observe(this, Observer {
            LjyLogUtil.d("switchMapLiveData.observe.onChanged:${it}")
        })
        liveData1.value = "123"
        liveData2.value = "456"
        liveData0.value = false
        //5. 合并多个LiveData数据源
        //MediatorLiveData继承自mutableLiveData,它将多个LiveData数据源集合起来,一个组件监听多个LiveData数据变化的目的
        val mediatorLiveData=MediatorLiveData<String>()
        mediatorLiveData.addSource(liveData0, Observer {
            LjyLogUtil.d("mediatorLiveData.addSource(liveData0):$it")
        })
        mediatorLiveData.addSource(liveData1, Observer {
            LjyLogUtil.d("mediatorLiveData.addSource(liveData1):$it")
        })
        mediatorLiveData.addSource(liveData2, Observer {
            LjyLogUtil.d("mediatorLiveData.addSource(liveData2):$it")
        })
        mediatorLiveData.observe(this, Observer {
            LjyLogUtil.d("mediatorLiveData.observe:$it")

        })
        liveData1.value = "321"
        liveData2.value = "654"
        //6. LiveData实例使用setValue()(主线程)/postValue()(子线程) 更新源数据
        LjyLogUtil.d("onCreate")
        mMutableLiveData.value = "value=onCreate"
        GlobalScope.launch {
            liveData0.postValue(true)
            delay(2000)
            mMutableLiveData.postValue("value=GlobalScope")
            liveData0.postValue(false)
        }
    }

    override fun onStart() {
        super.onStart()
        LjyLogUtil.d("onStart")
        mMutableLiveData.value = "value=onStart"
    }

    override fun onResume() {
        super.onResume()
        LjyLogUtil.d("onResume")
        mMutableLiveData.value = "value=onResume"
    }

    override fun onPause() {
        super.onPause()
        LjyLogUtil.d("onPause")
        mMutableLiveData.value = "value=onPause"
    }

    override fun onStop() {
        super.onStop()
        LjyLogUtil.d("onStop")
        mMutableLiveData.value = "value=onStop"
    }

    override fun onDestroy() {
        super.onDestroy()
        LjyLogUtil.d("onDestroy")
        mMutableLiveData.value = "value=onDestroy"
    }
}
  • 上面的更新数据源方法setValue()(主线程)/postValue()(子线程),主要是为了区分调用场景,其代码如下
@MainThread
protected void setValue(T value) {
    assertMainThread("setValue");
    mVersion++;
    mData = value;
    dispatchingValue(null);
}

protected void postValue(T value) {
    boolean postTask;
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        mPendingData = value;
    }
    if (!postTask) {
        return;
    }
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
//postValue方法把Runable对象mPostValueRunnable抛到主线程,其run方法中还是使用的setValue()
private final Runnable mPostValueRunnable = new Runnable() {
    @SuppressWarnings("unchecked")
    @Override
    public void run() {
        Object newValue;
        synchronized (mDataLock) {
            newValue = mPendingData;
            mPendingData = NOT_SET;
        }
        setValue((T) newValue); //也是走到setValue方法
    }
};

拓展LiveData对象

//1. 自定义LiveData
class MyLiveData(context: Context) : LiveData<String>() {
    init {
        LocationUtil.getInstance().getLocation(context)
    }

    companion object {
        var instance: MyLiveData? = null
        fun get(context: Context): MyLiveData? {
            if (instance == null) {
                instance = MyLiveData(context)
            }
            return instance
        }
    }

    val callback = LocationUtil.CallBack() {
        //注意这里的value(setValue)对应使用时的observe
        value = it
    }

    override fun onActive() {
        super.onActive()
        LjyLogUtil.d("MyLiveData.onActive")
        LocationUtil.getInstance().setCallBack(callback)
    }

    override fun onInactive() {
        super.onInactive()
        LjyLogUtil.d("MyLiveData.onInactive")
        LocationUtil.getInstance().removeCallBack()
    }
}
//2. 使用:
MyLiveData.get(this)?.observe(this, Observer {
    LjyLogUtil.d("LiveDataActivity:$it")
})
  • 当LiveData对象具有Active状态的观察者时调用onActive方法,才会有监听(setCallBack),当LiveData对象没有任何Active状态的观察者时调用onInactive方法,会移除监听(removeCallBack),callBack的onCall()中绑定了数据value = it,所以observe()可以观察到实时数据;

LiveData原理

  • 经过上面的使用我们发现LiveData和RxJava很相似,都是用的观察者模式,不同的是LiveData不是通知所有的观察者,而是只通知Active状态的观察者,那么这是如何做到的呢?

LiveData观察组件生命周期

  • 我们知道LiveData是通过observe()来注册观察者,那么以此为入口来看看其代码是如何实现的
  • 从observe()的第二行可以看到判断了getCurrentState() == DESTROYED则return,说明如果组件为DESTROYED状态是不允许注册为观察者的
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    assertMainThread("observe");
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // ignore
        return;
    }
    //owner, observer的包装类
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    //将observer和LifecycleBoundObserver存储到SafeIterableMap<Observer<? super T>, ObserverWrapper>
    ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    if (existing != null && !existing.isAttachedTo(owner)) {
    //不能添加同一个observer却不同LifecycleOwner
        throw new IllegalArgumentException("Cannot add the same observer"
                + " with different lifecycles");
    }
    //当前owner已经添加过了则return
    if (existing != null) {
        return;
    }
    //将LifecycleBoundObserver添加到Lifecycle中完成注册
    owner.getLifecycle().addObserver(wrapper);
}

// 除了使用observe()方法添加观察者,也可以使用observeForever(Observer) 方法来注册
// 未关联 LifecycleOwner的观察者。在这种情况下,观察者会被视为始终处于活跃状态;
@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);
}

private class AlwaysActiveObserver extends ObserverWrapper {
     AlwaysActiveObserver(Observer<? super T> observer) {
         super(observer);
     }
     @Override
     boolean shouldBeActive() {
         return true;
     }
 }
  • 再来看看LifecycleBoundObserver,它是LiveData的内部类
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
    @NonNull
    final LifecycleOwner mOwner;

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

    //判断当前传入的组件的状态是否是Active (STARTED和RESUMED状态)
    @Override
    boolean shouldBeActive() {
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    }

    //组件状态发生变化时,会调用onStateChanged方法
    @Override
    public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
        if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
            //DESTROYED状态时,移除observer
            removeObserver(mObserver);
            return;
        }
        //调用父类的方法
        activeStateChanged(shouldBeActive());
    }

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

    @Override
    void detachObserver() {
        mOwner.getLifecycle().removeObserver(this);
    }
}
  • 上面组件状态发生变化时,会调用onStateChanged(),onStateChanged中调用了父类的activeStateChanged(),其代码如下,可以看到activeStateChanged会根据Active状态和处于Active状态的组件的数量,来对onActive方法和onInactive方法回调,这两个方法用于拓展LiveData对象;
private abstract class ObserverWrapper {
    final Observer<? super T> mObserver;
    boolean mActive;
    int mLastVersion = START_VERSION;

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

    abstract boolean shouldBeActive();

    boolean isAttachedTo(LifecycleOwner owner) {
        return false;
    }

    void detachObserver() {
    }

    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);
        }
    }
}
  • 上面代码的最后,如果是Active状态,会调用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;
}
  • 上面分发方法最终会调用considerNotify(),其代码如下,
private void considerNotify(ObserverWrapper observer) {
    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的onChanged方法,这个方法正是使用LiveData的observe方法的回调

我是今阳,如果想要进阶和了解更多的干货,欢迎关注微信公众号 “今阳说” 接收我的最新文章

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

推荐阅读更多精彩内容