小知识,大挑战!本文正在参与“ 程序员必备小知识 ”创作活动

本文同时参与「掘力星计划」 ,赢取创作大礼包,挑战创作激励金

注意:本文LiveData相关使用及源码均是2.1.0版本

简介

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

如果观察者(由Observer类表示)的生命周期处于STARTEDRESUMED状态,则 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?) {
   
        valviewModel=ViewModelProvider(this)[MyViewModel::class.java]
    viewModel.getName().observe(this, Observer<String>{ name ->
      // update UI
    })
  }
}

原理分析

我们知道 livedata 的使用很简单,它是采用观察者模式实现的

  1. 添加观察者
  2. 在数据改变的时候设置 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
publicvoidobserve(@NonNullLifecycleOwnerowner,@NonNullObserver<?superT>observer){
//限定只能在主线程调用observe方法
assertMainThread("observe");
//当Lifecycle已经处于DESTROYED状态时,此时进行observe是没有意义的,直接返回
if(owner.getLifecycle().getCurrentState()==DESTROYED){
//ignore
return;
}
//根据传入参数构建一个新的代理Observer
LifecycleBoundObserverwrapper=newLifecycleBoundObserver(owner,observer);
//将observer作为key,wrapper作为value进行存储
//当mObservers不包含该key时,调用putIfAbsent会返回null
//当mObservers已包含该key时,调用putIfAbsent不会存储key-value,并会返回之前保存的value
ObserverWrapperexisting=mObservers.putIfAbsent(observer,wrapper);
if(existing!=null&&!existing.isAttachedTo(owner)){
//走到此步,说明之前LiveData内部已经持有了observer对象,
            //且该observer对象已经绑定了其它的LifecycleOwner对象
//此时直接抛出异常
thrownewIllegalArgumentException("Cannotaddthesameobserver"
+"withdifferentlifecycles");
}
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的整个事件流程是这样的:

  1. Lifecycle的生命周期发生变化,从而回调了onStateChanged函数
  2. onStateChanged函数首先判断Lifecycle是否已处于DESTROYED状态,是的话则直接移除Observer,整个回调流程结束,否则则继续以下流程
  3. 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 只能接收到最新值)的可能性的。