LiveData使用与源码分析

一、认识LiveData

LiveData是Google JetPack组件中的生命周期感应组件,自带生命周期管理。它可以很方便地帮我们管理MVVM模式中界面数据的自动化更新。我们可以理解LiveData是一个具有生命周期自感应的数据容器,也是LiveData的核心特色。

二、LiveData的使用

LiveData的使用一般配合ViewModel使用。在ViewModel中定义LiveData值,在Activity中订阅。

2.1 基础使用

  • 如实例所示,在ViewModel中定义LiveData,一般定义LiveData时会定义一个对内可修改的私有属性,对外提供一个只读的公开属性,只读LiveData指向内部可写LiveData,在UI层(例子中是MainActivity)订阅公开的只读的LiveData,如此将每次ViewModel的内部的LiveData值的变更都能传递到UI层通过公开LiveData订阅的观察者。
MainViewModel 复制代码
class MainViewModel: ViewModel() {

    /**
     * 数1
     */
    private val _numOneLiveData = MutableLiveData<Int>()
    val numOneLiveData: LiveData<Int> = _numOneLiveData

    /**
     * 数2
     */
    private val _numTwoLiveData = MutableLiveData<Int>()
    val numTwoLiveData: LiveData<Int> = _numTwoLiveData
    ...
    
    }
MainActivity 复制代码
class MainActivity : ComponentActivity() {

    private val viewModel by viewModels<MainViewModel>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        observeLiveData()
    }

    private fun observeLiveData() {
        // 观测数1
        viewModel.numOneLiveData.observe(this) {
            it.toString()
        }
        // 观测数2
        viewModel.numTwoLiveData.observe(this) {
            it.toString()
        }
    }
}

2.2 进阶使用

  • 场景一:在2.1的例子中,每个LiveData都对应一个独立的观测场景。我们更近一步的需求是,在UI层不仅需要观测numOne和numTwo的值,还希望显示两个数的和,且要观测两数之和。这种情况下,可以通过使用MediatorLiveData来实现该功能:定义一个MediatorLiveData类型的result,通过给result添加source,则可以在source对象发生变更时及时通知到result对象,从而完成其他值的变更监听,响应变化。
MainViewModel 复制代码
class MainViewModel: ViewModel() {
    ...
    init {
        _result.addSource(numOneLiveData) {
            val one = it?:return@addSource
            val two = numTwoLiveData.value?:return@addSource
            _result.value = two + one
        }

        _result.addSource(numTwoLiveData) {
            val one = numOneLiveData.value?:return@addSource
            val two = it?:return@addSource
            _result.value = two + one
        }

    }

    fun inc(type: Type) {
        when (type) {
            is Type.One -> {
                _numOneLiveData.value = (_numTwoLiveData.value?:0) + 1
            }
            is Type.Two -> {
                _numTwoLiveData.value = (_numTwoLiveData.value?:0) + 1
            }
        }
    }

    fun des(type: Type) {
        when (type) {
            is Type.One -> {
                _numOneLiveData.value = (_numOneLiveData.value?:0) + 1
            }
            is Type.Two -> {
                _numTwoLiveData.value = (_numTwoLiveData.value?:0) + 1
            }
        }
    }

}

三、LiveData的使用注意事项

3.1 关于订阅LiveData

  • 对LiveData对象使用observe(LifecycleOwner, Observer<? super T>)注册监听时,无需手动解除监听,无需担忧内存泄漏问题。

LiveData对象会对注册进来的observer根据LifecycleOwner进行管理,在onStop阶段进入非活跃状态,在destroy状态解除绑定。

  • 对LiveData对象使用observeForever(Observer<? super T>)注册监听时,与生命周期无绑定关系,需手动解除监听,否则可能存在内存泄漏的隐患。

使用这个函数注册的观察者会一直处于活跃状态。对所有的观察者实时分发变更。具体源码解析部分可以往下看,观察者在传递到内部实际会被转化为AlwaysActiveObserver对象。

  • 当调用LiveData的observe方法时,若此时LiveData有值,订阅者符合活跃状态的判定,则LiveData的机制是会立即回调当前值。若需要修改这里的机制,可以通过继承LiveData自行实现。
  • 对于LiveData监听的主动解除函数调用,需要保证在主线程中调用,使用时需要特别注意。
LiveData 复制代码
@MainThread 
public void removeObservers(@NonNull final LifecycleOwner owner) { 
    assertMainThread("removeObservers");
    ... 
}

@MainThread public void removeObserver(@NonNull final Observer<?super T> observer) {
    assertMainThread("removeObserver");
    ... 
}

3.2 关于LiveData写值

  • LiveData#setValue(T)只可在主线程调用,子线程调用会抛出异常。

setValue(T)的更新值方式是直接更新,除了更新值本身,也会更新一个mVersion字段来标记当前值的版本,setValue(T)函数也对主线程做了注解标记@MainThread,同时函数内也做了断言判断,所以如果在子线程调用会抛出异常。

  • LiveData#postValue(T)是子线程更新LiveData的方案。post出来的数据若消费不及时,可能发生数据未被消费就被覆盖的情况的,从而出现数据丢失的情况。

postValue(T)的实现原理是通过使用mPendingData来保存post的数据,mPendingData的数据会在内部post出去的runnable内部类的实例中被消费,若mPendingData数据被消费,则值会被重置为NOT_SET。若mPendingData未被消费时,外部调用postValue函数只会修改mPendingData的值,等待未被执行的runnable执行时被消费。

LiveData 复制代码
protected void postValue(T value) {
    boolean postTask;
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        mPendingData = value;
    }
    if (!postTask) {
        return;
    }
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
  • setValue(T)postValue(T)混用注意事项。

postValue(T)的函数源码中,官方的注释说明中明确提醒,当先调用postValue(T)再调用setValue(T),最后生效的值会是postValue(T)写入的值,所以当一个公开的LiveData数据,需要注意修改者的调用方式和调用顺序,避免出现不符合预期的结果。

四、深入理解LiveData的工作机制

4.1 关于LiveData本身

LiveData是一个抽象类,无法被实例化。其派生出来的公开的可直接使用的子类包括:MutableLiveDataMediatorLiveDataMutableLiveData提供了可读可写的能力,而MediatorLiveData提供了LiveData监听LiveData的能力,提供了LiveData更多的组合灵活性。还有一些系统内部自己实现的LiveData内部的派生类:CoroutineLiveDataLoaderManagerImpl.LoaderInfoSavedStateHandle.SavingStateLiveData,系统应用于特定的业务场景,感兴趣的同学可以深入源码再细读。

  • LiveData的构造函数默认支持两种:带初始值和不带初始值。
    • 关于值的设置:LiveData中用来记录具体数值的mData对象会被设置为NOT_SET值,NOT_SET是LiveData用来标记是否无值状态的对象,同样它也被用在postValue函数用来标记mPendingData对象,从而实现一些逻辑控制。
    • 关于值的版本:LiveData内部使用一个mVersion变量来标记mData值的版本,
LiveData 复制代码
/**
* Creates a LiveData initialized with the given {  @code  value}.
*
*  @param  value initial value
*/
public LiveData(T value) {
    mData = value;
    // 一旦开始写值,版本号就会从默认值开始累积
    mVersion = START_VERSION + 1; // static final int START_VERSION = -1;
}

/**
* Creates a LiveData with no value assigned to it.
*/
public LiveData() {
    mData = NOT_SET;
    mVersion = START_VERSION;
}

4.2 LiveData的线程安全问题

  • LiveData写值的线程安全保障:setValue(T)postValue(T)

LiveData的postValue是允许在子线程调用的,所以对mPendingData的写值需要做线程安全控制,mPendingData的写值使用了对象锁mDataLock来做访问控制。mData使用volatile修饰来保证线程可见性。

LiveData 复制代码
@SuppressWarnings("WeakerAccess") /* synthetic access */
volatile Object mPendingData = NOT_SET;
final Object mDataLock = new Object();

private volatile Object mData;

private final Runnable mPostValueRunnable = new Runnable() {
    @SuppressWarnings("unchecked")
    @Override
    public void run() {
        Object newValue;
        // 读写加锁
        synchronized (mDataLock) {
            newValue = mPendingData;
            mPendingData = NOT_SET;
        }
        setValue((T) newValue);
    }
};

@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);
}
  • LiveData订阅非线程安全:订阅者的管理使用的是非线程安全的容器,所以LiveData的observe和removeObserve函数都限定在主线程调用,同时函数有线程断言,若发现在非主线程中调用会立即抛出异常。
LiveData 复制代码
private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
        new SafeIterableMap<>();
        
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    assertMainThread("observe");
    ...
}
      
@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
    assertMainThread("observeForever");
    ...
}

@MainThread
public void removeObserver(@NonNull final Observer<? super T> observer) {
    assertMainThread("removeObserver");
    ...
}

@MainThread
public void removeObservers(@NonNull final LifecycleOwner owner) {
    assertMainThread("removeObservers");
    ...
}

4.3 当我们调用obsserve函数发生了什么?

这里从常用的observe(LifecycleOwner, Observer)函数分析。 从代码中可以发现,当LifcycleOwner的状态在DESTROYED状态时。observe调用为无效调用,会直接被忽略。接下来就是正常流程:

  1. 将owner和observer对象包装到LifecycleBoundObserver类型的wrapper对象中(LifecycleBoundObserver是LifecycleEventObserver接口的实现类)
  2. 在LiveData内部会有一个map来存储observer和wrapper的映射,不允许重复添加,否则抛出异常
  3. 给传入的owner的Lifecycle注册监听对象wrapper
LiveData 复制代码
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    assertMainThread("observe");
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // ignore
        return;
    }
    // 1. 对象二次包装
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    // 2. 是否重复添加判断
    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;
    }
    // 3.向owner订阅Lifecycle change事件
    owner.getLifecycle().addObserver(wrapper);
}

我们知道observe调用的同时,若LiveData处于有值的状态时,observer会被立即回调,这部分的逻辑代码则实现在LifecycleBoundObserver实现的LifecycleEventObserve接口定义的onStateChange(LifecycleOwner, Lifecycle.Event)函数中。 在该函数的实现中:

  1. 对DESTROYED过滤,对观察者进行移除
  2. 根据生命周期状态对外进行活跃状态的分发,activeStateChanged(boolean)的实现在其父类ObserverWrapper中,它会根据mActive状态是否变更来决定是否分发value给observer
LifecycleBoundObserver 复制代码
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
    ...

    @Override
    public void onStateChanged(@NonNull LifecycleOwner source,
            @NonNull Lifecycle.Event event) {
        Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
        // 1. 对DESTROYED过滤
        if (currentState == DESTROYED) {
            removeObserver(mObserver);
            return;
        }
        // 2. 根据生命周期状态对外进行活跃状态的分发
        Lifecycle.State prevState = null;
        while (prevState != currentState) {
            prevState = currentState;
            // 3. activeStateChanged的实现在父类ObserverWrapper中
            activeStateChanged(shouldBeActive());
            currentState = mOwner.getLifecycle().getCurrentState();
        }
    }
    

    @Override
    boolean shouldBeActive() {
        // 根据当前的生命周期阶段进行判断
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    }

    ...
}
  1. 最终会调用到LiveData的dispatcherValue(ObserverWrapper)函数中的considerNotify(ObserverWrapper)函数。在该函数中:
    • 若当前为非活跃状态,则会将当前的不活跃状态更新到observer中,待下次再次出发lifecycle state change时,响应当页面转化为活跃状态后能收到数据变更回调;
    • 若当前为活跃状态,则立即回调当前的observer的onChange函数发出的mData值。
LiveData 复制代码
@SuppressWarnings("WeakerAccess") /* synthetic access */
void dispatchingValue(@Nullable ObserverWrapper initiator) {
    ...
    do {
        mDispatchInvalidated = false;
        // 首次订阅走的是if成立的逻辑
        if (initiator != null) {
            considerNotify(initiator);
            initiator = null;
        } else {
            ...
        }
    } while (mDispatchInvalidated);
    mDispatchingValue = false;
}

@SuppressWarnings("unchecked")
private void considerNotify(ObserverWrapper observer) {
    if (!observer.mActive) {
        return;
    }
   
    // 若当前为非活跃状态,则会将当前的不活跃状态更新到observer中
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;
    observer.mObserver.onChanged((T) mData);
}

4.4 LiveData如何根据LifecycleOwner的生命周期对订阅者进行管理?

这部分和订阅过程的分析有部分重叠,由4.3部分,我们可知在observer被调用onChange前需要对LifecycleOwner的Lifecycle State做对应的处理。 而当Lifecycle state为Destroy时,Observer需要解除绑定。解除绑定的行为在LifecycleBoundObserveronStateChange(LifecycleOwner, Lifecycle.Event)中执行,由于LifecycleBoundObserver是一个内部类,可直接访问LiveData的函数,通过调用LiveData的removeObserve(Observer)解除LiveData的observer在LiveData队列中的引用,同时移除LifecycleOwner中的Lifecycle Change的监听。

LiveData 复制代码
public abstract class LiveData<T> {
    @MainThread
    public void removeObserver(@NonNull final Observer<? super T> observer) {
        assertMainThread("removeObserver");
        ObserverWrapper removed = mObservers.remove(observer);
        if (removed == null) {
            return;
        }
        // 移除Lifecycle的observer
        removed.detachObserver();
        removed.activeStateChanged(false);
    }

    class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
        ...
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
            if (currentState == DESTROYED) {
                // 移除观察者
                removeObserver(mObserver);
                return;
            }
            ...
        }
        
        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }
        ...
    }
}
相关推荐
alexhilton14 小时前
MVI架构:Compose中的响应式状态管理
android·kotlin·android jetpack
Wgllss18 小时前
大型异步下载器(二):基于kotlin+Compose+协程+Flow+Channel+ OKhttp 实现多文件异步同时分片断点续传下载
android·架构·android jetpack
_一条咸鱼_19 小时前
Android Runtime内存管理全体系解构(46)
android·面试·android jetpack
_一条咸鱼_1 天前
Android Runtime堆内存动态扩展策略原理(51)
android·面试·android jetpack
_一条咸鱼_1 天前
Android Runtime标记-清除垃圾回收核心流程原理(52)
android·面试·android jetpack
_一条咸鱼_2 天前
Android Runtime堆内存架构设计(47)
android·面试·android jetpack
_一条咸鱼_2 天前
Android Runtime增量编译与差分更新机制原理(45)
android·面试·android jetpack
_一条咸鱼_3 天前
Android Runtime二进制镜像(ART Image)生成原理(44)
android·面试·android jetpack
_一条咸鱼_3 天前
Android Runtime全局优化与跨函数分析原理(43)
android·面试·android jetpack
alexhilton4 天前
使用用例(Use Case)以让Android代码更简洁
android·kotlin·android jetpack