导语
Jetpack简介及其它组件文章
还在担心View层的内存泄漏吗?还在担心一些空指针异常吗?LiveData帮你解决这些问题。
主要内容
- LiveData是什么
- LiveData的基本使用
- postValue和setValue有什么区别
- observe是如何收到通知的
- LiveData的粘性事件
- 如何解决LiveData的粘性事件
具体内容
LiveData是什么
- LiveData是一个数据持有类
- 能够感知组件的生命周期
- 持有的数据可以被观察者观察
简单地来说就是当LiveData持有的数据发生改变的时候,观察者在生命周期处于STARTED或RESUMED状态时,LiveData会更新通知给活跃的观察者。
LiveData的基本使用
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建一个LiveData
MutableLiveData mutableLiveData = new MutableLiveData<>();
//注册观察者
mutableLiveData.observe(this, new Observer() {
@Override
public void onChanged(String s) {
Log.d("LiveData", s);
}
});
//其它线程执行完任务对LiveData进行通知
new Thread(new Runnable() {
@Override
public void run() {
//postValue() 可以在任意线程使用
mutableLiveData.postValue("通知");
//setValue() 只能在主线程被调用
// mutableLiveData.setValue("通知");
}
}).start();
}
}
从上面的代码可以看出,LiveData的基本使用很简单,同时我在代码中注释讲setValue()
只能在主线程被调用,接下来我们深入源码再看一下。
postValue和setValue有什么区别
我们可以分别点击postValue和setValue方法,进入它们的源码进行观察。
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
/**
* Sets the value. If there are active observers, the value will be dispatched to them.
*
* 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");
mVersion++;
mData = value;
dispatchingValue(null);
}
我们可以先看setValue()
,可以看到setValue()
有个注解@MainThread
,方法上面也有注释This method must be called from the main thread.
,都表明了这个方法只能在主线程被调用。
我们再跟踪一下postValue方法。postValue方法执行了一行比较重要的代码:ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
看样子是交给主线程去执行一个Runnable
。我们进入这个Runnable
看一下。
private final Runnable mPostValueRunnable = new Runnable() {
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
//noinspection unchecked
setValue((T) newValue);
}
};
我们可以看到,Runnable
最终又调用了setValue()
。
看到这里我们就知道了,postValue()
和setValue()
的作用是相同的,区别是postValue()
可以在任意线程调用,setValue()
只能在主线程调用。
因为postValue()
可以在任意线程调用,所以mPendingData
使用了volatile
关键字,同时通过synchronized
对代码块进行加锁,来保证线程安全。
可以通过setValue
方法看到,mData
才是我们真正的数据持有者。
observe是如何收到通知的
我们来直接看源码,我们先看LiveData.observe()
方法。
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
LiveData.LifecycleBoundObserver wrapper = new LiveData.LifecycleBoundObserver(owner, observer);
LiveData.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);
}
其中LifecycleBoundObserver
持有了我们传入的Observer super T> observer
,最后放到了mObservers
这个对象了,这个对象是一个Map
,所以我们可以一对多。
owner.getLifecycle().addObserver(wrapper)
这个代码不重点讲了,这个是Lifecycle
提供的功能,如果不了解可以看我其它文章或者去网上找一下。总之就是把wrapper
和LifecycleOwner
的生命周期进行了绑定。
我们再来看setValue()
方法是如何通知的。
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
void dispatchingValue(@Nullable LiveData.ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
for (Iterator, LiveData.ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
private void considerNotify(LiveData.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;
//noinspection unchecked
observer.mObserver.onChanged((T) mData);
}
这段代码比较长,不要慌,很简单,有些代码不重要直接往下看。
直接看dispatchingValue(null)
到底做了啥。首先我们传入了null
,所以会走else
,我们看到这里使用Iterator
对mObservers
进行遍历,之前说到mObservers
是一个map
,然后取出值执行considerNotify(iterator.next().getValue())
方法,在considerNotify()
里,最终调用observer.mObserver.onChanged((T) mData)
,把结果回调给我们业务层。
LiveData的粘性事件
我们来看一段代码,想一下Log会如何输出。
public class MainActivity extends AppCompatActivity {
MutableLiveData mutableLiveData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mutableLiveData = new MutableLiveData<>();
mutableLiveData.postValue("----------------》通知1");
}
//点击事件 写在xml里了
public void observe(View view) {
mutableLiveData.observe(this, new Observer() {
@Override
public void onChanged(String s) {
Log.d("LiveData", s);
}
});
mutableLiveData.observe(this, new Observer() {
@Override
public void onChanged(String s) {
Log.d("LiveData", s);
}
});
}
}
我们有一个点击事件,放到了xml里,我们先postValue()
,通过点击按钮再注册observer
,会怎样呢?
2021-03-10 16:52:07.251 25476-25476/com.example.jetpack D/LiveData: ----------------》通知1
2021-03-10 16:52:07.251 25476-25476/com.example.jetpack D/LiveData: ----------------》通知1
居然也收到了通知,这是为什么呢?我们来通过源码看一下。
我们在LiveData.observe()
的时候,创建了LifecycleBoundObserver
,LifecycleBoundObserver
继承ObserverWrapper
,我们直接来看LifecycleBoundObserver
和ObserverWrapper
的代码。
class LifecycleBoundObserver extends LiveData.ObserverWrapper implements GenericLifecycleObserver {
//...
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
//...
}
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;
boolean wasInactive = LiveData.this.mActiveCount == 0;
LiveData.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive) {
onActive();
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
onInactive();
}
if (mActive) {
dispatchingValue(this);
}
}
}
LifecycleBoundObserver
最终还继承了LifecycleEventObserver
,LifecycleEventObserver
有一个方法onStateChanged()
,首先要了解onStateChanged()
方法是Lifecycle
提供的功能,如果不了解可以看我其它文章或者去网上找一下。总之就是在Lifecycle
的生命周期发生改变的时候调用,所以当LiveData.observer()
的时候,就会调用到onStateChanged()
,然后再调用到activeStateChanged()
,最终执行了dispatchingValue(this)
,这句很熟悉呀,就是和setValue()
最终执行的是一样的代码块。不同的是传入的参数不为空了,所以直接执行considerNotify(initiator)
,不用遍历了。我们再来看一下这个方法我们还没有讲到的地方。
private void considerNotify(LiveData.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;
//noinspection unchecked
observer.mObserver.onChanged((T) mData);
}
我们一直向下走,直接来到considerNotify
方法,重要的一行代码是observer.mLastVersion >= mVersion
,分别点击两个version
去看一下,就明白了,分别是ObserverWrapper
的版本号和LiveData
的版本号,ObserverWrapper
的版本号大于LiveData
的版本号时,我们就返回,反之则执行,也就是说在什么情况下会执行呢?
举例我们刚才的事例代码,当LiveData
创建的时候,mVersion
的版本号为-1
,当LiveData
执行setValue
的时候,执行mVersion++
结果为0
,刚创建ObserverWrapper
的时候,mLastVersion
的版本是-1
,这个时候-1 >= 0
的结果为false
,所以向下执行不会return
,把mVersion
赋值给ObserverWrapper
的mLastVersion
,防止多次被回调,最终执行observer.mObserver.onChanged((T) mData)
。
如何解决LiveData的粘性事件
网上大多数的方案是通过反射,在第一次observer
的时候,修改ObserverWrapper
的mLastVersion
的值。
我的解决方案有点不太一样,通过代理模式拦截observer
。
我也上传到github了,可以给俺点几个小星星,谢谢。
/**
* Created by guoshichao on 2021/3/10
* 非粘性LiveData事件
*/
public class NonStickyLiveData extends MutableLiveData {
static final int START_VERSION = -1;
private int mVersion = START_VERSION;
@Override
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer super T> observer) {
ObserverProxy observerProxy = new ObserverProxy<>(observer);
observerProxy.preventNextEvent = mVersion > START_VERSION;
super.observe(owner, observerProxy);
}
@Override
public void setValue(T value) {
mVersion++;
super.setValue(value);
}
private class ObserverProxy implements Observer {
@NonNull
private final Observer observer;
private boolean preventNextEvent = false;
ObserverProxy(@NonNull Observer observer) {
this.observer = observer;
}
@Override
public void onChanged(@Nullable T t) {
if (preventNextEvent) {
preventNextEvent = false;
return;
}
observer.onChanged(t);
}
}
}
如果这样写有问题或者会出现bug,欢迎大家联系我。
更多内容戳这里(整理好的各种文集)