likes
comments
collection
share

JetPack LiveData (源码分析) 面试

作者站长头像
站长
· 阅读数 26

LiveData属于 可观察的数据容器类,观察者模式是它们相同的基本设计模式。接下来我们结合源码逐步复习一波,便于在面试中对答如流。

一、LiveData

LiveData is a data holder class that can be observed within a given lifecycle. This means that an Observer can be added in a pair with a LifecycleOwner, and this observer will be notified about modifications (改变,修改)of the wrapped data only if the paired LifecycleOwner is in active state. LifecycleOwner is considered as active, if its state is STARTED or RESUMED. An observer added via observeForever is considered as always active and thus will be always notified about modifications. For those observers, you should manually call removeObserver.

An observer added with a Lifecycle will be automatically removed if the corresponding Lifecycle moves to DESTROYED state. This is especially useful for activities and fragments where they can safely observe LiveData and not worry about leaks: they will be instantly unsubscribed when they are destroyed.

In addition, LiveData has onActive and onInactive methods to get notified when number of active Observers change between 0 and 1. This allows LiveData to release any heavy resources when it does not have any Observers that are actively observing.

This class is designed to hold individual data fields of ViewModel, but can also be used for sharing data between different modules in your application in a decoupled fashion.

根据官网:

LiveData 是一个数据持有者类,可以在给定的生命周期内进行观察。这意味着可以将观察者与生命周期所有者配对添加,只有配对的生命周期所有者处于活动状态时(如果 LifecycleOwner 的状态是STARTED or RESUMED,则认为它处于活动状态),该观察者才会收到有关包装数据修改的通知。

通过 observeForever 添加的观察者被视为始终处于活动状态,因此会始终收到修改通知。对于这些观察者,应手动调用 removeObserver。

JetPack LiveData (源码分析) 面试

1、分析源码

JetPack LiveData (源码分析) 面试

下面代码不难看出LiveData是一个数据持有者mData便是数据。在下面代码可以看到,当注册监听者时,在observe方法内部,观察者与生命周期所有者配对添加到了LifecycleBoundOvserver中,LifecycleBoundOverver实现了LifecycleEventObserver 所以是可以监听生命周期变化的,并在通过ower.getLifecycle().addObserver(wrapper)将wrapper 和 生命周期所有者进行了监听绑定,所以当生命周期持有者(Activity/Fragment)发生生命周期变化时, LifecycleBoundObserver#onStateChanged 就会自动接收到生命周期变化消息,currentState == DESTROYED可以看出,如果当前生命周期是DESTROYED就会自动移除订阅者,所以开发者是不需要主动移除订阅者Observer的。

public abstract class LiveData<T> {
    private volatile Object mData;
    volatile Object mPendingData = NOT_SET;
    //版本号来记录数值的新旧程度。
    private int mVersion;
    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        assertMainThread("observe");//确保在主线程执行,否则抛出异常
        //当生命周期持有者状态处于DESTROYED时候直接return;
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        //观察者与生命周期所有者配对添加到wrapper
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
       
        //和生命周期所有者owner进行监听绑定。
        owner.getLifecycle().addObserver(wrapper);
    }
    
    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() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }
    
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
            //如果当前生命周期是DESTROYED就会移除订阅者。
            if (currentState == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            Lifecycle.State prevState = null;
            while (prevState != currentState) {
                prevState = currentState;
                activeStateChanged(shouldBeActive());
                currentState = mOwner.getLifecycle().getCurrentState();
            }
        }
    
        @Override
        boolean isAttachedTo(LifecycleOwner owner) {
            return mOwner == owner;
        }
    
        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }
    }
    
}

在上述代码 while (prevState != currentState) 可以看到,接收到生命周期状态,和发生变化之前的生命周期状态做比对,如果不同调用ObserverWrapper#activeStateChanged(shouldBeActive())方法。这里的shouldBeActive方法,不难找到其比较的是生命状态枚举序列大小。

//需要知道LifecycleBoundOvserver实现了ObserverWrapper
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
 //...................
}

private abstract class ObserverWrapper {
    final Observer<? super T> mObserver;
    boolean mActive;
    //这里需要知道,每次注册监听者默认初始化mLastVersion是START_VERSION = -1
    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;
        changeActiveCounter(mActive ? 1 : -1);
        if (mActive) {
            dispatchingValue(this);
        }
    }
}

本质代码如下 Enum#compareTo(E o){...return self.ordinal - other.ordinal} 不难看出,return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED)、即如果生命周期状态枚举序列大于等于STARTED也就是(STARTED or RESUMED)返回true,上面ObserverWrapper#activeStateChanged才往下继续执行,最终调用了dispatchingValue(this),开始分发数据流程。

//lifecycle生命周期状态枚举
public enum State {
DESTROYED, 
    
INITIALIZED,
    
CREATED,
    
STARTED,

RESUMED;
    /**
* Compares if this State is greater or equal to the given { @code state}.
*
* @param state State to compare with
* @return true if this State is greater or equal to the given { @code state}
*/
public boolean isAtLeast(@NonNull State state) {
        return compareTo(state) >= 0;
    }
}
//Enum.java 枚举类
public abstract class Enum{
    public final int compareTo(E o) {
        Enum<?> other = (Enum<?>)o;
        Enum<E> self = this;
        if (self.getClass() != other.getClass() && // optimization
            self.getDeclaringClass() != other.getDeclaringClass())
            throw new ClassCastException();
        return self.ordinal - other.ordinal;//比较枚举序列号
    }
}

数据分发流程、可以看到分如果当前正在分发那么会被return掉,保证此次分发完成不受干扰,否则通过do..while中判断如果当前ObserverWrapper实例initiator不为null优先调用considerNotify通知观察者,否则遍历所有观察者在considerNotify(ObserverWrapper observer)中分发进行通知每个观察者。

void dispatchingValue(@Nullable ObserverWrapper initiator) {
    // 检查是否已经在分发过程中
    if (mDispatchingValue) {
        // 如果是,设置分发无效标志位并返回
        mDispatchInvalidated = true;
        return;
    }
    // 标记开始分发
    mDispatchingValue = true;
    do {
        // 重置分发无效标志位
        mDispatchInvalidated = false;
        // 如果 initiator 不为空,首先通知 initiator
        if (initiator != null) {
            considerNotify(initiator);
            // 之后将 initiator 置为 null,这样下次循环时不会重复通知
            initiator = null;
        } else {
            // 否则遍历所有观察者
            for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                // 通知每一个观察者
                considerNotify(iterator.next().getValue());
                // 如果在通知期间 mDispatchInvalidated 被设置为 true,退出循环
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
    // 如果在通知期间 mDispatchInvalidated 被设置为 true,重新开始分发过程
    } while (mDispatchInvalidated);
    // 标记分发结束
    mDispatchingValue = false;
}

这里 if (initiator != null) 和 else 对应的场景是什么呢 ?

通过查看dispatchingValue调用部分不难发现,在外部通过postValue和setValue进行设置分发数据时如下面,都是dispatchingValue(null),走else最终循环遍历所有监听者进行通知。而在LiveData.obser注册的监听者在出现生命周期发生变化,且状态活跃时在ObserverWrapper#activeStateChanged中通过dispatchingValue(this);所以只通知给传入的监听者。以及LiveData.observeForever在注册监听时,通过ObserverWrapper#activeStateChanged直接分发给了监听者。

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

分发部分代码如下:


@SuppressWarnings("unchecked")
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;
    }
    //判断如果观察者的版本小于当前版本才回去分发。
    //确保每个观察者不会在同一个版本的数据上接收到多次通知,避免重复通知。
    //也就是在一次setValue到下发完成,一个接收者不会在这次下发过程中接收到多次重复通知。
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;
    observer.mObserver.onChanged((T) mData);
}


private abstract class ObserverWrapper {
    final Observer<? super T> mObserver;
    boolean mActive;
    //这里需要知道,每次注册监听者默认初始化mLastVersion是START_VERSION = -1
    int mLastVersion = START_VERSION;
}


//版本号每次setValue都会mVersion++
@MainThread
protected void setValue(T value) {
    assertMainThread("setValue");
    mVersion++;
    mData = value;
    dispatchingValue(null);
}

可以看到只有当前监听者的最新版本号小于当前版本才会继续通知监听者。mVersion在每次LiveData.setValue中都会mVersion++,而每个观察者oberver初始化mLastVersion = -1,下发数据成功之后设置observer.mLastVersion = mVersion,确保每个观察者不会在同一个版本的数据上接收到多次通知,避免重复通知。

源码看到这里,我们看到了当生命周期持有者(Activity,或者Fragment等),在生命周期发生变化之后,实现了LifecycleEventObserver 并 绑定了生命周期所有者监听的 LifecycleBoundObserver 会自动根据生命周期状态判断下发数据操作。这也是在使用LiveData时候,如果强行与行为或事件绑定,在屏幕旋转或者页面重建,会出现重复执行上次事件或者行为的问题,很多人称其为 “数据倒灌”

2、数据倒灌

通过上述源码分析,在生命周期发生变化,且满足生命周期所有者处于活动状态时(STARTED or RESUMED),会将上一次最后的数据mData再次下发给监听者。LiveData设计的目的是数据读取分发,而开发过程中如果将其用来处理行为或事件可能会出现所说的 "数据倒灌"。

  • 具体发生场景

页面有一个土司,放置在liveData监听者里面显示:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    viewModel.mLiveData.observe(this) { data->
    Toast.makeText(this,data.toString(), Toast.LENGTH_LONG).show()
    }
}

当屏幕发生旋转,系统语言设置,分屏等操作场景时,onCreate重建时候,我们为LiveData注册了一个新的监听者,在LiveData#obser方法中,初始化LifecycleBoundObserver,它实现了ObserverWrapper,所以ObserverWrapper被初始化,而mLastVersion版本初始化为START_VERSION= -1,过程:下面代码步骤(1步->2步->3步)。

当生命周期走到onResume时,根据上述源码分析由于LifecycleBoundObserver实现了LifecycleEventObserver所以当生命周期变化且活跃状态,进行自动下发数据,在considerNotify最后分发之前有(observer.mLastVersion >= mVersion)判断,而observer 即上面的ObserverWrapper其mLastVersion = -1 肯定是小于 mVersion的。所以通过调用observer.mObserver.onChanged((T) mData);将mData上次的数据会分发给监听者,导致了土司再次弹出。

public abstract class LiveData<T> {
    private volatile Object mData;
    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        //.......1步.....
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        //............
        owner.getLifecycle().addObserver(wrapper);
    }
    //.......2步.....
    class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
  
    }
    
    private abstract class ObserverWrapper {
        final Observer<? super T> mObserver;
        boolean mActive;
        //.......3步.....
        //这里需要知道,每次注册监听者默认初始化mLastVersion是START_VERSION = -1
        int mLastVersion = START_VERSION;
    }
    
    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.
        //判断如果观察者的版本小于当前版本才回去分发。
        //确保每个观察者不会在同一个版本的数据上接收到多次通知,避免重复通知。
        //也就是在一次setValue到下发完成,一个接收者不会在这次下发过程中接收到多次重复通知。
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);
   }
}
  • 解决方案

根据上述源码分析,很清楚关键在于每次注册监听者,初始化LifecycleBoundObserver,ObserverWrapper初始化时候,mLastVersion版本被初始化为START_VERSION= -1,导致最终分发(35行继续像后面执行,并没有return结束)到监听者。所以解决方案也很简单,网上也有很多方案其中之一**UnPeekLiveData** 在初始化ObserverWrapper时候进行初始化mLastVersion为当前版本,这样再分发时候会进入return。结束分发,也达到了解决需求。但这样还是不是LiveData设计的初衷呢,又带给开发者多少的疑惑。对于事件或者行为方式在我看来就不应该糅合到具有生命周期感知的LiveData中,而从数据的恢复和分发这个出发点来说,LiveData又有什么错呢?

3、observeForever

不同于observe方法,observeForever并没有和生命周期所有者进行绑定。直接通过调用 wrapper.activeStateChanged(true) 进行数据分发,参数直接传递true,ObserverWrapper中的mActive被赋值为true,在后面分发中也不用判断是否是生命周期活跃状态,直接下发。每次注册监听者都会立马分发给监听者,更像是粘性事件。

需要注意:observeForever不受Lifecycle影响,需要手动移除。

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进行数据分发,更像粘性事件
    wrapper.activeStateChanged(true);
}

private class AlwaysActiveObserver extends ObserverWrapper {

    AlwaysActiveObserver(Observer<? super T> observer) {
        super(observer);
    }

    @Override
    boolean shouldBeActive() {
        return true;
    }
}

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;
        changeActiveCounter(mActive ? 1 : -1);
        if (mActive) {
            dispatchingValue(this);
        }
    }
}

4、postValue 丢失数据

开发者在高频调用postTask方法时候,mPendingData会被多次赋值,而mPostValueRunnable被执行之前并不能保证mPendingData不被多次赋值。而ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);也可能因为主线程的任务队列阻塞或延迟,而多次调用postValue。导致最终分发的数据mPendingData为最后一次postValue的数据。

  1、首次postValue 进来,mPendingData默认是NOT_SET,所以postTask 被赋值为true,mPendingData 赋值为value,跳过 if (!postTask) 继续执行。当执行到Runnable时,mPendingData尚未被赋值NOT_SET,如果此时有其他postValue进来,postTask = mPendingData == NOT_SET 是false(因为mPendingData尚未被赋值为NOT_SET),当执行到 if (!postTask) 时直接return了,导致数据丢失。


final Object mDataLock = new Object();
volatile Object mPendingData = NOT_SET;

private final Runnable mPostValueRunnable = new Runnable() {
    @SuppressWarnings("unchecked")
    @Override
    public void run() {
        Object newValue;//此时mPendingData还未被赋值为NOT_SET.
        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);
}

5、map

map 操作符可以将 LiveData 分发的数据类型转换为另一种数据类型。

所分析源代码版本:androidx.lifecycle:lifecycle-livedata-core-ktx:2.6.1

不难看出LiveData.map是一个扩展函数,其自身的数据类型X,而return返回Y类型的MediatorLiveData。根据源码MediatorLiveData实现了MutableLiveData即LiveData。而MediatorLiveData内部定义了一个mSources作为作为全局集合变量进行储存当前LiveData和Source便于移除等操作。而Source类实现了Observer,并在构造参数传入了当前LiveData,通过 e.plug() 注册观察者Source。当数据所有变化时,Source内部的 onChange 监听到,通过注入的observer回调通知到LiveData.map的result.addSource(this){这里},然后给新的LiveData即MediatorLivedata赋值,通知更新。

@JvmName("map")
@MainThread
@CheckResult
fun <X, Y> LiveData<X>.map(mapFunction: Function<X, Y>): LiveData<Y> {
    val result = MediatorLiveData<Y>()
    result.addSource(this) { x -> result.value = mapFunction.apply(x) }
return result
}

public interface Function<I, O> {
    /**
* Applies this function to the given input.
*
* @param input the input
* @return the function result.
*/
O apply(I input);
}


//MediatorLiveData 实现了MutableLiveData
public class MediatorLiveData<T> extends MutableLiveData<T> {
    private SafeIterableMap<LiveData<?>, Source<?>> mSources = new SafeIterableMap<>();

    /**
* Creates a MediatorLiveData with no value assigned to it.
*/
public MediatorLiveData() {
        super();
    }

    /**
* Creates a MediatorLiveData initialized with the given { @code value}.
*
* @param value initial value
*/
public MediatorLiveData(T value) {
        super(value);
    }

    /**
* Starts to listen to the given { @code source} LiveData, { @code onChanged} observer will be
* called when { @code source} value was changed.
* <p>
* { @code onChanged} callback will be called only when this { @code MediatorLiveData} is active.
* <p> If the given LiveData is already added as a source but with a different Observer,
* { @link IllegalArgumentException} will be thrown.
*
* @param source    the { @code LiveData} to listen to
* @param onChanged The observer that will receive the events
* @param <S>       The type of data hold by { @code source} LiveData
*/
@MainThread
    public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
        if (source == null) {
            throw new NullPointerException("source cannot be null");
        }
        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();
        }
    }

    //实现了Observe,便于接受liveData在有新数据时onChanged监听到。
    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);
            }
        }
    }
}

public class MutableLiveData<T> extends LiveData<T> {

    /**
* Creates a MutableLiveData initialized with the given { @code value}.
*
* @param value initial value
*/
public MutableLiveData(T value) {
        super(value);
    }

    /**
* Creates a MutableLiveData with no value assigned to it.
*/
public MutableLiveData() {
        super();
    }

    @Override
    public void postValue(T value) {
        super.postValue(value);
    }

    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
}

代码示例如下,将ModelData类型的 LiveData 转化为Usage类型的 LiveData,useAgeLiveData 仅仅处理Usage相关UI模块,减少不必要的耦合。当然过多的 liveData 也会导致ViewModel膨胀,造成代码编写的难度。这个就需要谈到MVI架构了。

private val _chatLiveData = MutableLiveData<ModelData>()
val useAgeLiveData: LiveData<Usage?> = _chatLiveData.map(transform = { x -> x.usage } )

6、switchMap

区别于map,switchMap其参数类型transform是一个方法类型参数,且方法类型返回的类型也是LiveData。而方法局部也是定义了一个result的MediatorLiveData,将当前LiveData和监听添加到了MediatorLiveData的全局集合遍历mSources中,同map一样。当LiveData有数值变化时,会回调到object:Observer{}里面,而transform再onChanged局部被调用,且创建了一个newLiveData,并在通过result.addSource(liveData!!),同样添加到了result的mSources内部,当transform 中创建得liveData有数据设置时,将会在result.addSource(liveData!!){y->...}

回调函数中拿到数据并设置给result。这样外部通过switchMap转换后的LiveData所注册的监听者将会收到数据。


@JvmName("switchMap")
@MainThread
@CheckResult
fun <X, Y> LiveData<X>.switchMap(
    transform: (@JvmSuppressWildcards X) -> (@JvmSuppressWildcards LiveData<Y>)?
): LiveData<Y> {
    val result = MediatorLiveData<Y>()
    result.addSource(this, object : Observer<X> {
        var liveData: LiveData<Y>? = null

        override fun onChanged(value: X) {
            val newLiveData = transform(value)
            if (liveData === newLiveData) {
                return
            }
            if (liveData != null) {
                result.removeSource(liveData!!)
            }
            liveData = newLiveData
            if (liveData != null) {
                result.addSource(liveData!!) { y -> result.setValue(y) }
}
        }
    })
    return result
}

代码示例如下:

当_chatLiveData数据改变时,switchMap内部的result.addSource的observer回调中onChanged接收到数据X类型的value,接着上面源码 transform(value),调用了下面注册部分的transform = {x->} 中,并通过getUsage(x.id)获取了需要的类型数据Usage,最终设置给局部的MutableLiveData并返回赋值给newLiveData,接着在上面(22行)将新的liveData同样的方式添加到了MediatorLiveData中,同样在下面赋值useAge之后会在源码(22行)的lambda中通过result.setValue,最终在Activity注册的监听者接收数据。

private val _chatLiveData = MutableLiveData<ModelData>()

val useLiveData: LiveData<Usage?> = _chatLiveData.switchMap(transform = { x ->
val useAge = getUsage(x.id)
    MutableLiveData<Usage?>().apply {
 value = useAge
    }
} )

class MainActivity... {
    .....
    override fun on create(saveInstanceState:Bundle?){
    
    
       viewModel.useLiveData.observe(this) {
useText.text = it?.name
       }
    }
}

7、distinctUntilChanged

LiveData并没有过滤重复值的操作,即使反复设置相同的数值,最终也会通知给监听者。对于频繁调用的某些场景也许同样的数据高频率的刷新赋值没有必要,可能造成UI抖动等。所以官方扩展了方法来过滤重复数据问题。源代码如下,当 previousValue !=null && previousValue != value (上一次得值和当前要分发的不一样)时候才会继续分发,达到过滤的重复值的效果。

fun <X> LiveData<X>.distinctUntilChanged(): LiveData<X> {
    val outputLiveData = MediatorLiveData<X>()
    var firstTime = true
    if (isInitialized) {
        outputLiveData.value = value
firstTime = false
    }
    outputLiveData.addSource(this) { value ->
val previousValue = outputLiveData.value
if (firstTime ||
            previousValue == null && value != null ||
            previousValue != null && previousValue != value
        ) {
            firstTime = false
            outputLiveData.value = value
        }
    }
return outputLiveData
}

二、总结

LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,当相应的 Lifecycle 对象的状态变为 DESTROYED 时,便可移除此观察者,而不必担心泄露(当 activity 和 fragment 的生命周期被销毁时,系统会立即退订它们)。当然将LiveData可能出现数据丢失或用来处理事件和行为可能出现一些比较棘手的问题,开发者需要注意,当然解决方案很多(魔改、反射、用协程代替)。

最后说一下个人体会,2020年开始使用Jetpack系列框架LiveData、后来替换为Flow、Hilt、完全使用Compose、MVVM 到 MVI 过程架构分层更加清晰明了,以及效率显著提高,不同的架构选择不一样,LiveData有自己适合得场景,它并非无所不能,而开发者应该明白其职责以及场景问题的背后本质,就可以在遇到问题时选择更加适合技术或框架解决问题。

转载自:https://juejin.cn/post/7377361330699059209
评论
请登录