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);
        }
        ...
    }
}
相关推荐
一航jason8 天前
Android Jetpack Compose 现有Java老项目集成使用compose开发
android·java·android jetpack
帅次9 天前
Android CoordinatorLayout:打造高效交互界面的利器
android·gradle·android studio·rxjava·android jetpack·androidx·appcompat
IAM四十二12 天前
Jetpack Compose State 你用对了吗?
android·android jetpack·composer
Wgllss13 天前
那些大厂架构师是怎样封装网络请求的?
android·架构·android jetpack
x0241 个月前
Android Room(SQLite) too many SQL variables异常
sqlite·安卓·android jetpack·1024程序员节
alexhilton1 个月前
深入理解观察者模式
android·kotlin·android jetpack
Wgllss1 个月前
花式高阶:插件化之Dex文件的高阶用法,极少人知道的秘密
android·性能优化·android jetpack
上官阳阳1 个月前
使用Compose创造有趣的动画:使用Compose共享元素
android·android jetpack
沐言人生1 个月前
Android10 Framework—Init进程-15.属性变化控制Service
android·android studio·android jetpack
IAM四十二1 个月前
Android Jetpack Core
android·android studio·android jetpack