Android Jetpack架构组件——LiveData原理篇

2024-02-29 07:58

本文主要是介绍Android Jetpack架构组件——LiveData原理篇,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

前面我们讲到了LiveData是如何使用的,并在最后留了几个问题。比如它是如何通过生命周期去变化的?为什么DESTORY不会接受数据?postValue和setValue是如何更新数据的?Transformations的map和switchMap方法内部是如何操作的?别急,本篇文章会带你了解其原理。接下来上正文。

LiveData是如何观察生命周期变化的?

如何观察生命周期,我们需要通过他的observe方法去看,我们上源码:

    @MainThreadpublic void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {assertMainThread("observe");//1if (owner.getLifecycle().getCurrentState() == DESTROYED) {// ignorereturn;}//2LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);//3ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);//4if (existing != null && !existing.isAttachedTo(owner)) {throw new IllegalArgumentException("Cannot add the same observer"+ " with different lifecycles");}if (existing != null) {return;}//5owner.getLifecycle().addObserver(wrapper);}

我在源码加了几个注释,我们一个个看。

注释一:可以看出通过当前组件的LifecycleOwner拿到生命周期的状态,如果是DESTORY就返回,不做任何处理。

注释二:新建了一个LifecycleBoundObserver包装类,并把owner和observer丢进去。

注释三:将observer和wrapper做一个存储。我们看下putIfAbsent方法:

public V putIfAbsent(@NonNull K key, @NonNull V v) {Entry<K, V> entry = get(key);if (entry != null) {return entry.mValue;}put(key, v);return null;}

可以看出,如何这个entry存在的话,不像正常map做替换,而且直接拿到对应的value。不存在的话正常put操作。

注释四:判断这个owner是否存在,如何存在就抛出异常,提示无法添加具有不同生命周期的同一观察者。

注释五:将LifecycleBoundObserver添加到Lifecycle中完成注册,所以我们LiveData的生命周期观察其实来源于LifecycleOwner,这也就是为什么LiveData具备了观察组件生命周期变化的能力。

observe是如何同步数据的?

上面代码中我们知道有一个LifecycleBoundObserver的包装类。我们看看其实现逻辑:

class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {@NonNullfinal LifecycleOwner mOwner;LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {super(observer);mOwner = owner;}@Overrideboolean shouldBeActive() {return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);}@Overridepublic void onStateChanged(@NonNull LifecycleOwner source,@NonNull Lifecycle.Event event) {Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();if (currentState == DESTROYED) {removeObserver(mObserver);return;}Lifecycle.State prevState = null;while (prevState != currentState) {prevState = currentState;activeStateChanged(shouldBeActive());currentState = mOwner.getLifecycle().getCurrentState();}}@Overrideboolean isAttachedTo(LifecycleOwner owner) {return mOwner == owner;}@Overridevoid detachObserver() {mOwner.getLifecycle().removeObserver(this);}}

我们来关注几个方法。通过ObserverWrapper实现了shouldBeActive。从命名上可以看出判读是否活跃。从代码看来也就是STARTED和RESUMED。

在看另一个,通过LifecycleEventObserver实现了onStateChanged方法。我们可以看到如果当前的STATE是DESTROYED时会移除观察者监听。接着通过判读状态是否匹配调用了activeStateChanged方法。因为prevState定义为null。所以此方法最少执行一次。那么我们看看它是如何处理的。

void activeStateChanged(boolean newActive) {if (newActive == mActive) {return;}// immediately set active state, so we'd never dispatch anything to inactive// ownermActive = newActive;changeActiveCounter(mActive ? 1 : -1);if (mActive) {dispatchingValue(this);}}

可以看到它会先调用changeActiveCounter,字面意思也就是改变活跃的数量。

@MainThreadvoid changeActiveCounter(int change) {int previousActiveCount = mActiveCount;mActiveCount += change;if (mChangingActiveState) {return;}mChangingActiveState = true;try {while (previousActiveCount != mActiveCount) {boolean needToCallActive = previousActiveCount == 0 && mActiveCount > 0;boolean needToCallInactive = previousActiveCount > 0 && mActiveCount == 0;previousActiveCount = mActiveCount;if (needToCallActive) {onActive();} else if (needToCallInactive) {onInactive();}}} finally {mChangingActiveState = false;}}

从逻辑上我们可以看出previousActiveCount默认为0,mActiveCount可能为1,可能为-1,mChangingActiveState默认为flase。也就是一定会走进while循环里面去。从里面代码可以看出需要通知组件存活状态就调用onActive,需要通知组件不活跃就调用onInactive。然后我们往回看,如果组件是活跃的就会调用dispatchingValue方法。我们接着看:

    void dispatchingValue(@Nullable ObserverWrapper initiator) {//1if (mDispatchingValue) {//2mDispatchInvalidated = true;return;}mDispatchingValue = true;do {//3mDispatchInvalidated = 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);//4mDispatchingValue = false;}

注释一中mDispatchingValue用于标记当前是否处于分发状态中,如果是存在分发状态,则执行注释二表示分发无效并直接return。注释三则将分发状态修改成有效状态。我们可以看到后面无论initiator是否为null都会执行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;observer.mObserver.onChanged((T) mData);}

可以看到当前状态如果是非活跃的就直接return了。接着判读了如果当前observer对应组件的状态不是Active,就会再次调用activeStateChanged方法,并传入false,其方法内部会再次判断是否执行onActive方法和onInactive方法回调。接着就会调用Observer的onChange方法通知数据更新。

postValue和setValue的区别是什么?

我们知道虽然我们调用observe方法对数据进行观察,但是真正同步数据的代码是postValue和setValue。话不多说,上代码:

    private final Runnable mPostValueRunnable = new Runnable() {@SuppressWarnings("unchecked")@Overridepublic void run() {Object newValue;synchronized (mDataLock) {newValue = mPendingData;mPendingData = NOT_SET;}setValue((T) newValue);}};...protected void postValue(T value) {boolean postTask;synchronized (mDataLock) {postTask = mPendingData == NOT_SET;mPendingData = value;}if (!postTask) {return;}ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);}@MainThreadprotected void setValue(T value) {assertMainThread("setValue");mVersion++;mData = value;dispatchingValue(null);}

我们看到setValue加上了@MainThread注解,也就是在主线程中执行,并且会调用dispatchingValue传入null。这个前面我们有提到过。而postValue其实是在子线程操作,最后通过postToMainThread同步至主线程,最后其实还是调用了setValue方法。

Transformations分析

前面我们在使用篇时有提到Transformations有2个方法,一个是map。一个是switchMap。我们一个个的看。

map
 @MainThread@NonNullpublic 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>() {@Overridepublic void onChanged(@Nullable X x) {result.setValue(mapFunction.apply(x));}});return result;}

我们可以看到此处调用了MediatorLiveData的addSource方法:

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

可以看到最后一个判断,如果存在活跃的观察者,即调用Source的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);}@Overridepublic void onChanged(@Nullable V v) {if (mVersion != mLiveData.getVersion()) {mVersion = mLiveData.getVersion();mObserver.onChanged(v);}}}

我们可以看到Source提供了添加观察者,移除观察者,以及监听的操作。哎,不对,是不是发现哪里有点问题?这里它调用的是observeForever,而不是addObserver。那我们接着看:

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

可以看出,这里最后其实还是调用了ObserverWrapper的activeStateChanged方法。

switchMap
    @MainThread@NonNullpublic 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;@Overridepublic 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>() {@Overridepublic void onChanged(@Nullable Y y) {result.setValue(y);}});}}});return result;}

可以看出来,整体和map类似,只是内部包装了一层,让其返回结果是一个LiveData而已。

总结

本篇我们整体介绍了LiveData的使用原理,也就是上篇文章遗留下来的几个问题。总之,我们不仅需要知其然,还需要知其所以然。

参考

Android Jetpack架构组件(五)带你了解LiveData(原理篇)

本文首发于我的个人博客:Android Jetpack架构组件——LiveData原理篇

更多文章请关注我的公众号:码农职场

在这里插入图片描述

这篇关于Android Jetpack架构组件——LiveData原理篇的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/758065

相关文章

Android中Dialog的使用详解

《Android中Dialog的使用详解》Dialog(对话框)是Android中常用的UI组件,用于临时显示重要信息或获取用户输入,本文给大家介绍Android中Dialog的使用,感兴趣的朋友一起... 目录android中Dialog的使用详解1. 基本Dialog类型1.1 AlertDialog(

Java异常架构Exception(异常)详解

《Java异常架构Exception(异常)详解》:本文主要介绍Java异常架构Exception(异常),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. Exception 类的概述Exception的分类2. 受检异常(Checked Exception)

Android Kotlin 高阶函数详解及其在协程中的应用小结

《AndroidKotlin高阶函数详解及其在协程中的应用小结》高阶函数是Kotlin中的一个重要特性,它能够将函数作为一等公民(First-ClassCitizen),使得代码更加简洁、灵活和可... 目录1. 引言2. 什么是高阶函数?3. 高阶函数的基础用法3.1 传递函数作为参数3.2 Lambda

Vue中组件之间传值的六种方式(完整版)

《Vue中组件之间传值的六种方式(完整版)》组件是vue.js最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用,针对不同的使用场景,如何选择行之有效的通信方式... 目录前言方法一、props/$emit1.父组件向子组件传值2.子组件向父组件传值(通过事件形式)方

Android自定义Scrollbar的两种实现方式

《Android自定义Scrollbar的两种实现方式》本文介绍两种实现自定义滚动条的方法,分别通过ItemDecoration方案和独立View方案实现滚动条定制化,文章通过代码示例讲解的非常详细,... 目录方案一:ItemDecoration实现(推荐用于RecyclerView)实现原理完整代码实现

Android App安装列表获取方法(实践方案)

《AndroidApp安装列表获取方法(实践方案)》文章介绍了Android11及以上版本获取应用列表的方案调整,包括权限配置、白名单配置和action配置三种方式,并提供了相应的Java和Kotl... 目录前言实现方案         方案概述一、 androidManifest 三种配置方式

Spring组件初始化扩展点BeanPostProcessor的作用详解

《Spring组件初始化扩展点BeanPostProcessor的作用详解》本文通过实战案例和常见应用场景详细介绍了BeanPostProcessor的使用,并强调了其在Spring扩展中的重要性,感... 目录一、概述二、BeanPostProcessor的作用三、核心方法解析1、postProcessB

kotlin中的行为组件及高级用法

《kotlin中的行为组件及高级用法》Jetpack中的四大行为组件:WorkManager、DataBinding、Coroutines和Lifecycle,分别解决了后台任务调度、数据驱动UI、异... 目录WorkManager工作原理最佳实践Data Binding工作原理进阶技巧Coroutine

Android WebView无法加载H5页面的常见问题和解决方法

《AndroidWebView无法加载H5页面的常见问题和解决方法》AndroidWebView是一种视图组件,使得Android应用能够显示网页内容,它基于Chromium,具备现代浏览器的许多功... 目录1. WebView 简介2. 常见问题3. 网络权限设置4. 启用 JavaScript5. D

Android如何获取当前CPU频率和占用率

《Android如何获取当前CPU频率和占用率》最近在优化App的性能,需要获取当前CPU视频频率和占用率,所以本文小编就来和大家总结一下如何在Android中获取当前CPU频率和占用率吧... 最近在优化 App 的性能,需要获取当前 CPU视频频率和占用率,通过查询资料,大致思路如下:目前没有标准的