Jetpack全家桶之LiveData使用及源码篇
Posted 初一十五啊
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Jetpack全家桶之LiveData使用及源码篇相关的知识,希望对你有一定的参考价值。
简介
LiveData
是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。
如果观察者(由 Observer
类表示)的生命周期处于 STARTED
或 RESUMED
状态,则 LiveData 会认为该观察者处于活跃状态。LiveData 只会将更新通知给活跃的观察者。为观察 LiveData
对象而注册的非活跃观察者不会收到更改通知。
您可以注册与实现 LifecycleOwner
接口的对象配对的观察者。有了这种关系,当相应的 Lifecycle
对象的状态变为 DESTROYED
时,便可移除此观察者。这对于 Activity 和 Fragment 特别有用,因为它们可以放心地观察 LiveData
对象,而不必担心泄露(当 Activity 和 Fragment 的生命周期被销毁时,系统会立即退订它们)。
LiveData 的优势
-
确保界面符合数据状态 LiveData 遵循观察者模式。当底层数据发生变化时,LiveData 会通知
Observer
对象。您可以整合代码以在这些Observer
对象中更新界面。这样一来,您无需在每次应用数据发生变化时更新界面,因为观察者会替您完成更新。 -
不会发生内存泄漏 观察者会绑定到
Lifecycle
对象,并在其关联的生命周期遭到销毁后进行自我清理。 -
不会因 Activity 停止而导致崩溃 如果观察者的生命周期处于非活跃状态(如返回栈中的 Activity),则它不会接收任何 LiveData 事件。
-
不再需要手动处理生命周期 界面组件只是观察相关数据,不会停止或恢复观察。LiveData 将自动管理所有这些操作,因为它在观察时可以感知相关的生命周期状态变化。
-
数据始终保持最新状态 如果生命周期变为非活跃状态,它会在再次变为活跃状态时接收最新的数据。例如,曾经在后台的 Activity 会在返回前台后立即接收最新的数据。
-
适当的配置更改 如果由于配置更改(如设备旋转)而重新创建了 Activity 或 Fragment,它会立即接收最新的可用数据。
-
共享资源 您可以使用单例模式扩展
LiveData
对象以封装系统服务,以便在应用中共享它们。LiveData
对象连接到系统服务一次,然后需要相应资源的任何观察者只需观察LiveData
对象。如需了解详情,请参阅 扩展 LiveData。
依赖引入
如果你的项目引入了androidx.appcompat:appcompat:***
包,默认LiveData已经引入
Kotlin
dependencies
val lifecycle_version = "2.4.0-alpha02"
// LiveData
implementation("androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version")
Java
dependencies
val lifecycle_version = "2.4.0-alpha02"
// LiveData
implementation("androidx.lifecycle:lifecycle-livedata:$lifecycle_version")
基本使用
class MyViewModel : ViewModel()
val name = MutableLiveData<String>()
private fun getName()
name.value="数据内容"
class MyActivity : AppCompatActivity()
override fun onCreate(savedInstanceState: Bundle?)
val viewModel = ViewModelProvider(this)[MyViewModel::class.java]
viewModel.getName().observe(this, Observer<String> name ->
// update UI
)
原理分析
我们知道 livedata 的使用很简单,它是采用观察者模式实现的
- 添加观察者
- 在数据改变的时候设置 value,这样会回调 Observer 的 onChanged 方法
public interface Observer<T>
/**
* Called when the data is changed.
* @param t The new data
*/
void onChanged(T t);
observe方法
LiveData包含两个用于添加数据观察者(Observer)的方法,分别是
- observe(LifecycleOwner , Observer)
生命周期安全的
- observeForever(Observer)
两个方法的区别对于外部来说只在于是否提供了生命周期安全的保障。
生命周期安全的observe
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer)
//限定只能在主线程调用 observe 方法
assertMainThread("observe");
//当 Lifecycle 已经处于 DESTROYED 状态时,此时进行 observe 是没有意义的,直接返回
if (owner.getLifecycle().getCurrentState() == DESTROYED)
// ignore
return;
//根据传入参数构建一个新的代理 Observer
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
//将 observer 作为 key,wrapper 作为 value 进行存储
//当 mObservers 不包含该 key 时,调用 putIfAbsent 会返回 null
//当 mObservers 已包含该 key 时,调用 putIfAbsent 不会存储 key-value,并会返回之前保存的 value
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner))
//走到此步,说明之前 LiveData 内部已经持有了 observer 对象,
//且该 observer 对象已经绑定了其它的 LifecycleOwner 对象
//此时直接抛出异常
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
if (existing != null)
//observer 之前已经传进来过了,此处直接返回
return;
owner.getLifecycle().addObserver(wrapper);
传入的LifecycleOwner
参数意味着携带了Lifecycle对象,LiveData内部就根据 Lifecycle的生命周期事件的回调变化在合适的时机进行数据通知,并在 Lifecycle对象处于DESTROYED状态时自动移除Observer,这也是LiveData避免内存泄漏的最重要的一个点。
上面的代码使用到了LifecycleBoundObserver
,它是抽象类ObserverWrapper的实现类。ObserverWrapper用于包装外部传进来的Observer对象,为子类定义好特定的抽象方法和共用逻辑,主要是提供了共用的状态分发函数。
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer)
super(observer);
mOwner = owner;
@Override
boolean shouldBeActive()
//只有当 Lifecycle 的当前状态是 STARTED 或者 RESUMED 时
//才认为 Lifecycle 是处于活跃状态
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
//LifecycleEventObserver 的实现方法
//当 Lifecycle 的生命周期状态发生变化时就会调用此方法
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event)
//如果 Lifecycle 已经处于 DESTROYED 状态了,则主动移除 mObserver
//这就是 LiveData 可以避免内存泄露最重要的一个点
if (mOwner.getLifecycle().getCurrentState() == DESTROYED)
removeObserver(mObserver);
return;
activeStateChanged(shouldBeActive());
@Override
boolean isAttachedTo(LifecycleOwner owner)
return mOwner == owner;
@Override
void detachObserver()
//移除 mObserver
mOwner.getLifecycle().removeObserver(this);
LifecycleBoundObserver的整个事件流程是这样的:
- Lifecycle的生命周期发生变化,从而回调了onStateChanged函数
- onStateChanged函数首先判断Lifecycle是否已处于DESTROYED状态,是的话则直接移除Observer,整个回调流程结束,否则则继续以下流程
- onStateChanged调用了activeStateChanged()函数,activeStateChanged()函数判断Lifecycle的活跃状态是否发生了变化,如果从非活跃状态切换到了活跃状态,是的话则调用dispatchingValue()函数来分发值,最终再根据ObserverWrapper内部的value版本号mLastVersion来判断是否有新值需要向其回调,是的话则向其回调新值,否则则返回
private abstract class ObserverWrapper
//外部传进来的对 LiveData 进行数据监听的 Observer
final Observer<? super T> mObserver;
//用于标记 mObserver 是否处于活跃状态
boolean mActive;
//用于标记 Observer 内最后一个被回调的 value 的新旧程度
int mLastVersion = START_VERSION;
ObserverWrapper(Observer<? super T> observer)
mObserver = observer;
//用于获取当前 Lifecycle 是否处于活跃状态
abstract boolean shouldBeActive();
//用于判断 mObserver 是否和 LifecycleOwner(即 Lifecycle)有绑定关系
boolean isAttachedTo(LifecycleOwner owner)
return false;
//移除 mObserver
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;
//判断当前 LiveData 所有的 Observer 是否都处于非活跃状态
boolean wasInactive = LiveData.this.mActiveCount == 0;
//更新 LiveData 当前所有处于活跃状态的 Observer 的数量
LiveData.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive)
//如果 LiveData 处于活跃状态的 Observer 数量从 0 变成了 1,
//则回调 onActive 方法
onActive();
if (LiveData.this.mActiveCount == 0 && !mActive)
//如果 LiveData 处于活跃状态的 Observer 数量从 1 变成了 0,
//则回调 onInactive 方法
onInactive();
if (mActive)
//如果 mObserver 变成了活跃状态,则向其回调新值
dispatchingValue(this);
ObserverWrapper一共有两个子类:
LifecycleBoundObserver和AlwaysActiveObserver,两者的差别就在于是否和生命周期相绑定。
非生命周期安全的observeForever
@MainThread
public void observeForever(@NonNull Observer<? super T> observer)
//限定只能在主线程调用 observe 方法
assertMainThread("observeForever");
AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing instanceof LiveData.LifecycleBoundObserver)
//会走到这一步,是因为之前已经先用该 observer 对象调用了 observe(LifecycleOwner,Observer)
//这里直接抛出异常
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
if (existing != null)
//如果之前已经添加过 observer 对象了的话,则直接返回
return;
//主动触发 activeStateChanged 函数,因为当前 LiveData 可能已经被设置值了
wrapper.activeStateChanged(true);
上面代码使用到了AlwaysActiveObserver,它也是抽象类ObserverWrapper的实现类,其shouldBeActive()返回值固定为true,意味着只要有数据变化都会进行回调。所以使用observeForever()函数一定要在过后主动移除Observer
,避免内存泄露和NPE。
更新LiveData的值
更新LiveData的值的方法一共有两个,分别是:
- setValue(T value)
- postValue(T value)
setValue
setValue(T)函数被限定在只能主线程进行调用。
/**
* Sets the value. If there are active observers, the value will be dispatched to them.
* <p>
* This method must be called from the main thread. If you need set a value from a background
* thread, you can use @link #postValue(Object)
*
* @param value The new value
*/
@MainThread
protected void setValue(T value)
assertMainThread("setValue");
//更新当前 value 的版本号,即 value 的新旧程度
mVersion++;
mData = value;
dispatchingValue(null);
dispatchingValue()
函数设计得比较巧妙,用两个全局的布尔变量mDispatchingValue和mDispatchInvalidated就实现了新旧值判断、旧值舍弃、新值重新全局发布的逻辑。
//initiator 为 null 则说明需要遍历回调整个 mObservers
//initiator 不为 null 则说明仅回调 initiator 本身
void dispatchingValue(@Nullable ObserverWrapper initiator)
//如果当前正处于向 mObservers 发布 mData 的过程中(即 mDispatchingValue 为 true)
//则将 mDispatchInvalidated 置为 true,用于标明有新值到来,正在回调的值是已经过时的了
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;
// 判断是否要将数据分发到指定的 ObserverWrapper
private void considerNotify(ObserverWrapper observer)
//如果 observer 处于非活跃状态,则直接返回
if (!observer.mActive)
return;
//此处判断主要是为了照顾 LifecycleBoundObserver
//由于 Lifecycle 有可能状态值 State 已经切换到了非活跃状态,但 LifecycleBoundObserver 还未收到事件通知
//所以为了避免意外情况,此处主动检查 observer 的活跃状态并判断是否需要更新其活跃状态
if (!observer.shouldBeActive())
observer.activeStateChanged(false);
return;
//根据 observer 本部的 value 版本号 mLastVersion 来决定是否需要向其进行回调
//为了避免重复向某个 observer 回调值,所以此处需要判断下
if (observer.mLastVersion >= mVersion)
return;
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
postValue
/**
* Posts a task to a main thread to set the given value. So if you have a following code
* executed in the main thread:
* <pre class="prettyprint">
* liveData.postValue("a");
* liveData.setValue("b");
* </pre>
* The value "b" would be set at first and later the main thread would override it with
* the value "a".
* <p>
* If you called this method multiple times before a main thread executed a posted task, only
* the last value would be dispatched.
*
* @param value The new value
*/
protected void postValue(T value)
boolean postTask;
synchronized (mDataLock)
postTask = mPendingData == NOT_SET;
mPendingData = value;
if (!postTask)
return;
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
postValue(T)函数不限定调用者所在线程,不管是主线程还是子线程都可以调用,因此是存在多线程竞争的可能性的,postValue(T)函数的重点旧在于需要理解其从子线程切换到主线程之间的状态变化。
在mPostValueRunnable被执行前,所有通过postValue(T)函数传递的value都会被保存到变量mPendingData上,且只会保留最后一个
,直到mPostValueRunnable被执行后mPendingData才会被重置,所以使用 postValue(T) 函数在多线程同时调用或者单线程连续调用的情况下是存在丢值(外部的 Observer 只能接收到最新值)的可能性的。
为方便大家系统的学习 Android JetPack全家桶完成内容 ,这里特意整理了一份 《Jetpack Compose 入门到精通》的学习手册,该手册条理清晰,含图像化表示更加易懂,非常适合想要进阶提升的伙伴,有需要的可以直接进行参考学习:https://0a.fit/GQJSl
一、Jetpack Compose入门详解
1.优势与缺点
2.Jetpack Compose 四节课
3.标准布局组件
4.xml和compose混合使用 + livedata数据绑定
5.compose结合navigation使用
6.Compose 中的 ConstraintLayout
7.Compose 手写一个分享二维码弹窗
8.Compose 设置颜色的三种方式
9.Compose事件与状态简略介绍
10.Compose中的预览@Preview与@PreviewParameter的使用
二、Compose学习笔记录
1.基本控件
2.Composable和MutableState
3.重组和无状态
4.状态机制和重组优化
5.derivedStateOf和remember的使用
6.CompositionLocal的应用场景
7.Compose动画之AnimateSpec
8.Compose动画之DecayAnimation
9.Compose动画之中止和入场效果
三、Android Compose 动画使用详解
1.Compose 中属性动画的使用探索
2.状态改变动画animateXxxAsState
3.自定义animateXxxAsState动画
Compose 需要学习的知识点还有许多,这还得一一的去探究其中的奥秘,该学习手册的内容还在持续更新中,有需要的可以直接进行参考学习:https://0a.fit/GQJSl
以上是关于Jetpack全家桶之LiveData使用及源码篇的主要内容,如果未能解决你的问题,请参考以下文章
4. Jetpack源码解析—LiveData的使用及工作原理
4. Jetpack源码解析—LiveData的使用及工作原理
4. Jetpack源码解析—LiveData的使用及工作原理
5. Jetpack源码解析---ViewModel基本使用及源码解析