Q:什么是LiveData?
LiveData
是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。
Q:请谈谈LiveData的好处
1.确保界面符合数据状态
LiveData 遵循观察者模式。当底层数据发生变化时,LiveData 会通知Observer
对象。您可以整合代码以在这些Observer
对象中更新界面。这样一来,您无需在每次应用数据发生变化时更新界面,因为观察者会替您完成更新。
2.不会发生内存泄露
观察者会绑定到Lifecycle
对象,并在其关联的生命周期遭到销毁后进行自我清理。
3.不会因 Activity 停止而导致崩溃
如果观察者的生命周期处于非活跃状态(如返回栈中的 Activity),则它不会接收任何 LiveData 事件。
4.不再需要手动处理生命周期
界面组件只是观察相关数据,不会停止或恢复观察。LiveData 将自动管理所有这些操作,因为它在观察时可以感知相关的生命周期状态变化。
5.数据始终保持最新状态
如果生命周期变为非活跃状态,它会在再次变为活跃状态时接收最新的数据。例如,曾经在后台的 Activity 会在返回前台后立即接收最新的数据。
6.适当的配置更改
如果由于配置更改(如设备旋转)而重新创建了 Activity 或 Fragment,它会立即接收最新的可用数据。
7.共享资源
您可以使用单例模式扩展LiveData
对象以封装系统服务,以便在应用中共享它们。LiveData
对象连接到系统服务一次,然后需要相应资源的任何观察者只需观察LiveData
对象。
Q:LiveData为什么可以自动取消订阅,如何避免内存泄漏?
调用 observe 方法时,会调用 owner.getLifecycle().addObserver 以达到感知生命周期的目的。
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
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.getLifecycle().addObserver(wrapper);
}
其中的观察者是owner和observer的包装对象LifecycleBoundObserver
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
@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(LifecycleOwner source, Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
当Lifecycles的State发生变化会回调onStateChanged方法,当State为DESTROYED时,则移除观察者Observer。里面调用的是LiveData的removeObserver方法。
public void removeObserver(@NonNull final Observer<? super T> observer) {
assertMainThread("removeObserver");
ObserverWrapper removed = mObservers.remove(observer);
if (removed == null) {
return;
}
removed.detachObserver();
removed.activeStateChanged(false);
}
当页面销毁时,在mObservers中remove了observer,就这样完成了订阅的自动取消。
Q:LiveData传相同的值会不会执行onchanged回调?
给LiveData传值有两种方式
setValue()
和postValue()
,它们之间的区别在于前者只能在主线程使用,后者可以在任意线程中调用,传入的数据会暂存为mPendingData,最终会使用Handler
切换回主线程中调用setValue(mPendingData)进行数据更新。
注意的是,postValue()被多次调用时,暂存数据mPendingData会被postValue()传入的数据覆盖,最终数据为最后一次的数据。而postValue()发起的主线程任务,在执行到之前,只会存在一个任务。
查看setValue方法:
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
注意mVersion的值,查看dispatchingValue方法:
void dispatchingValue(@Nullable ObserverWrapper initiator) {
....
considerNotify(initiator);
....
}
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;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
只要mVersion是大于等于之前的值,就会回调onChanged方法,也就是说,不管值是否相同,只看version的值。
Q:谈谈你对observeForever的认识?
// LiveData.java
@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
assertMainThread("observeForever");
// 创建AlwaysActiveObserver
AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing instanceof LiveData.LifecycleBoundObserver) {
// 如果existing是LiveData.LifecycleBoundObserver类的实例,抛出异常
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
// 调用AlwaysActiveObserver的activeStateChanged方法,并且传入true
wrapper.activeStateChanged(true);
}
再看下AlwaysActiveObserver的代码:
// LiveData.java
private class AlwaysActiveObserver extends ObserverWrapper {
AlwaysActiveObserver(Observer<? super T> observer) {
super(observer);
}
// 重写了shouldBeActive方法,并且返回true,根据上面的代码分析可知,这个方法是用来判断是否为活跃状态,这里一直返回true,也就是说一直保持着活跃状态
@Override
boolean shouldBeActive() {
return true;
}
}
observeForever是用于将指定的观察者添加到观察列表中,类似于调用observer方法,但是给定的LifecycleOwner状态总是为活跃状态,这意味着观察者将永远接收所有的事件,所以如果要停止观察这个LiveData,就要手动调用removeObserver方法。
Q:PostValue收不到数据变更的通知的问题是否遇到过?或者说使用PostValue需要注意的问题
当连续调用 postValue 时,有可能只会收到最后一次数据更新通知。
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
mPendingData
被成功赋值 value 后,post 了一个 Runnable
mPostValueRunnable 的实现如下:
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
setValue((T) newValue);
}
};
- postValue 将数据存入 mPendingData,mPostValueRunnable 在UI线程消费mPendingData。
- 在 Runnable 中 mPendingData 值还没有被消费之前,即使连续 postValue , 也不会 post 新的 Runnable
- mPendingData 的生产 (赋值) 和消费(赋 NOT_SET) 需要加锁
简单的说是因为:
postValue 只是把传进来的数据先存到 mPendingData,然后往主线程抛一个 Runnable,在这个 Runnable 里面再调用 setValue 来把存起来的值真正设置上去,并回调观察者们。而如果在这个 Runnable 执行前多次 postValue,其实只是改变暂存的值 mPendingData,并不会再次抛另一个 Runnable。这就会出现后设置的值把前面的值覆盖掉的问题,会导致事件丢失。
Q:为什么PostValue要设计为只post一次Runnable?
即使 post 多次也没有意义,所以只 post 一次即可。
对于 setValue 来说,连续调用多次,数据会依次更新:
如下,订阅方一次收到 a b 的通知:
liveData.setValue("a");
liveData.setValue("b");
通过源码可知,dispatchingValue()
中同步调用 Observer#onChanged()
,依次通知订阅方:
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
但对于 postValue,如果当 value 变化时,我们立即post,而不进行阻塞
protected void postValue(T value) {
mPendingData = value;
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
private final Runnable mPostValueRunnable = new Runnable() {
public void run() {
setValue((T) mPendingData);
}
};
由于线程切换的开销,连续调用 postValue,收到通知只能是b、b,无法收到a。
因此,post 多次已无意义,一次即可。
Q: 为什么要加读写锁?
是否 post 取决于对 mPendingData 的判断(是否为 NOT_SET)。因为要在多线程环境中访问 mPendingData ,不加读写锁无法保证其线程安全。
protected void postValue(T value) {
boolean postTask = mPendingData == NOT_SET; // --1
mPendingData = value; // --2
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
private final Runnable mPostValueRunnable = new Runnable() {
public void run() {
Object newValue = mPendingData;
mPendingData = NOT_SET; // --3
setValue((T) newValue);
}
};
如上,如果在 1 和 2 之间,执行了 3,则 2 中设置的值将无法得到更新。
Q:如何解决或防止LiveData或者MutableLiveData多次回调的问题
利用SingleLiveEvent 使 observe#LiveData时只相应一次onChanged操作
public class SingleLiveEvent<T> extends MutableLiveData<T> {
private static final String TAG = "SingleLiveEvent";
private final AtomicBoolean mPending = new AtomicBoolean(false);
@MainThread
public void observe(LifecycleOwner owner, final Observer<T> observer) {
if (hasActiveObservers()) {
Log.w(TAG, "Multiple observers registered but only one will be notified of changes.");
}
// Observe the internal MutableLiveData
super.observe(owner, new Observer<T>() {
@Override
public void onChanged(@Nullable T t) {
if (mPending.compareAndSet(true, false)) {
observer.onChanged(t);
}
}
});
}
@MainThread
public void setValue(@Nullable T t) {
mPending.set(true);
super.setValue(t);
}
/**
* Used for cases where T is Void, to make calls cleaner.
*/
@MainThread
public void call() {
setValue(null);
}
}
1.SingleLiveEvent 利用 AtomicBoolean (默认为false)进行赋值,当LiveData 进行 setValue时改变 AtomicBoolean的值(set(true)
2 使用 AtomicBoolean.compareAndSet(true,false)方法,先进行判断(此时的AtomicBoolean的值为true)与 compareAndSet设置的except值(第一个参数)比较,因为相等所以将第二个参数设置为AtomicBoolean值设为false函数并返回 true
- 当再次进入该页面虽然 LiveData值并没有改变,仍然触发了 observer方法,由于 AtomicBoolean已经为 false ,但是 except值为 true,与if 进行判断所以 并不会继续触发 onChanged(T)方法
即只有在 setValue时相应一次onChanged(T)方法。
Android消息总线的演进之路:用LiveDataBus替代RxBus、EventBus
ViewModel之外的LiveData-使用Transformations和MediatorLiveData的反应模式
Android面试:说一下 LiveData 的 postValue ?与SetValue有什么区别?连续调用会有什么问题?为什么?