JetPacket LiveData
本文主要介绍两方面的内容
- LiveData简单使用
- LiveData的粘包事件原因以及处理方式
LiveData简介
LiveData是可以在给定生命周期内观察到的数据持有者类。这意味着Observer可以配对添加LifecycleOwner,并且只有在配对的LifecycleOwner处于活动状态时,才会向该观察者通知有关包装数据的修改。如果LifecycleOwner状态为STARTED或RESUMED,则将其视为活动状态 。观察者添加 observeForever(Observer)被视为始终处于活动状态,因此将始终收到有关修改的通知。对于这些观察者,您应该手动调用 removeObserver(Observer)。
如果相应的生命周期移至DESTROYED状态,则添加了生命周期的观察者将被自动删除。这对于Activity和Fragment可以安全地观察LiveData而不用担心泄漏,对Activity特别有用:销毁它们时,它们将立即被取消订阅。
另外,当active的数量在0到1之间变化时,LiveData具有onActive()和onInactive()通知方法Observer。这使LiveData在没有任何Activity的观察者的情况下释放任何大量资源。
此类用于保存ViewModel的各个数据字段,但也可用于以解耦方式在应用程序中的不同模块之间共享数据。
LiveData简单使用
LiveData一般会结合LifeCycler和ViewModel使用
这里先创建一个ViewModel
public class NameViewModel extends ViewModel {
//创建一个可修改的LiveData,数据类型为String
private MutableLiveData<String> currentName;
public MutableLiveData<String> getCurrentName(){
if(currentName==null){
currentName=new MutableLiveData<>();
}
return currentName;
}
}
在Activity中使用LiveData
public class NameActivity extends AppCompatActivity {
private NameViewModel model;
private TextView nameTextView;
private Button btn;
private int i=0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_name);
nameTextView=findViewById(R.id.tvText);
btn=findViewById(R.id.btn);
//需要一个观察者来观察数据
Observer observer = new Observer<String>(){
@Override
public void onChanged(String s) {
nameTextView.setText(s);
}
};
//获取到viewmodel
model= ViewModelProviders.of(this).get(NameViewModel.class);
//取出livedata完成订阅,
//此处的this是lifecyclerowner,会自动绑定Activity的生命周期
model.getCurrentName().observe(this,observer);
btn.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
String anotherName="jett"+(i++);
//通过LiveData更新数据,调用setValue或者postValue之后,
//就会回调Observer的onChange方法
model.getCurrentName().setValue(anotherName);
}
});
}
}
LiveData的简单使用就介绍完了,总结一下就是分为以下几个步骤:
- 创建一个LiveData对象
- LiveData对象绑定相应的LifeCyclerOwner和Observer
- 调用setValue或者postValue更新数据,数据更新之后,LiveData会自动回调Observer的onChange方法
此处需要注意的是,setValue只能在UI线程调用,postValue是在子线程中调用,有兴趣的可以看源码,postValue最终还是转到UI线程通过setValue使数据更新生效
到这里可能大家会想,那如果有很多种不同类型的数据需要更新,那么是不是需要多个LiveData对象去处理不同的数据,这样写会很麻烦,此处可以考虑使用泛型,将项目中可能要使用到的不同类型的LiveData整合到一起,生成一个LiveDataBus。
public class LiveDataBus {
//存放订阅者
private Map<String, MutableLiveData<Object>> bus;
private static LiveDataBus liveDataBus = new LiveDataBus();
private LiveDataBus() {
bus = new HashMap();
}
public static LiveDataBus getInstance() {
return liveDataBus;
}
//注册订阅者
public synchronized <T> MutableLiveData<T> with(String key, Class<T> type) {
if(!bus.containsKey(key)){
bus.put(key,new MutableLiveData<Object>());
}
//这里使用强制转换,加上泛型,可以约定LiveData的数据类型
return (MutableLiveData<T>)bus.get(key);
}
}
LiveDataBus的使用
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void click(View view) {
if (view.getId() == R.id.btn) {
Intent intent = new Intent(this, NameActivity.class);
startActivity(intent);
} else if (view.getId() == R.id.btn2) {
Intent intent = new Intent(this, TestLiveDataBusActivity.class);
startActivity(intent);
new Thread(){
@Override
public void run() {
for (int i = 0; i < 10; i++) {
//发送消息
LiveDataBus.getInstance().with("data", String.class).postValue("xxx");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
}
}
public class TestLiveDataBusActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_livedatabus);
//绑定LifeCyclerOwner和Observer
//MainActivity中更新数据之后,就会回调此处Observer的onChange方法
LiveDataBus.getInstance().with("data", String.class)
.observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
if(s!=null)
Toast.makeText(TestLiveDataBusActivity.this, s, Toast.LENGTH_SHORT).show();
}
});
}
}
LiveData粘包事件
回顾一下LiveData的使用3步骤:
- 创建一个LiveData对象
- LiveData对象绑定相应的LifeCyclerOwner和Observer
- 调用setValue或者postValue更新数据,数据更新之后,LiveData会自动回调Observer的onChange方法
在上面的使用中,你会发现,在MainActivity中先通过startActivity启动TestLiveDataBusActivity,然后在线程中不断更新数据,在一开始更新数据的时候,TestLiveDataBusActivity还没执行声明周期函数onCreate,Observer还没有跟LiveData进行绑定订阅,但是在TestLiveDataBusActivity启动的时候,就会发现收到了之前MainActivity更新的消息。
如果严格按照上面1-2-3的顺序是没有什么疑问,但是目前我们的使用步骤其实是1-3-2,先更新了数据,然后才执行的绑定动作,但是依然收到了数据,这个就有问题了,很多时候,业务有一定的时序行,可能并不需要之前的数据,这样就出问题了。
LiveData的粘包就是只,先发送的数据,然后才绑定的Observer,但是Observer依然收到了回调,那么这个问题是怎么造成的呢?
其实是在setValue的时候,会将更新的值保存在mData这个成员变量中,绑定Observer的时候,调用observe方法,然后一步步最后会根据LifecyclerOwner的生命周期,根据相对应的State,等到发现当前的状态至少是STATED的时候,就去回调Observer的onChange方法
调用流程:
observe[LiveData.java]–>owner.getLifecycle().addObserver(wrapper)–>addObserver[LifecycleRegistry.java]–>statefulObserver.dispatchEvent–>dispatchEvent[LifecycleRegistry.java-ObserverWithState]–>mLifecycleObserver.onStateChanged–>onStateChanged[LiveData.java-LifecycleBoundObserver]–>activeStateChanged–>dispatchingValue–>considerNotify–>observer.mObserver.onChanged((T) mData)
//LiveData.java
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
//注意此处放进mObservers的是LifecycleBoundObserver
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;
}
//调用lifeCycler的addObserver方法,绑定Observer和LifecyclerOwner
owner.getLifecycle().addObserver(wrapper);
}
//LifecycleRegistry.java
@Override
public void addObserver(@NonNull LifecycleObserver observer) {
//初始状态为INITIALIZED
State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
......
State targetState = calculateTargetState(observer);
mAddingObserverCounter++;
//此处statefulObserver.mState为INITIALIZED
while ((statefulObserver.mState.compareTo(targetState) < 0
&& mObserverMap.contains(observer))) {
pushParentState(statefulObserver.mState);
//这里开始分发生命周期事件
statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
popParentState();
// mState / subling may have been changed recalculate
targetState = calculateTargetState(observer);
}
......
}
void dispatchEvent(LifecycleOwner owner, Event event) {
State newState = getStateAfter(event);
mState = min(mState, newState);
//生命周期更新
mLifecycleObserver.onStateChanged(owner, event);
mState = newState;
}
//LiveData.java
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
//这里需要注意shouldBeActive()方法
activeStateChanged(shouldBeActive());
}
@Override
boolean shouldBeActive() {
//当前的状态至少是STARTED的时候,才说明Lifecycler是处于Active状态
//DESTROYED,INITIALIZED,CREATED,STARTED,RESUMED
//也就是说,当前状态只有是STARTED或者RESUMED的时候才是Active
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive;
......
//当TestLiveDataBusActivity执行到onStart,onResume的时候,
//shouldBeActive()方法返回true,那么mActivity为true
if (mActive) {
dispatchingValue(this);
}
}
void dispatchingValue(@Nullable ObserverWrapper initiator) {
......
do {
mDispatchInvalidated = false;
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
......
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
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的onChange方法
observer.mObserver.onChanged((T) mData);
}
到这里,LiveData的粘包事件流程就理清楚了
粘包事件处理办法
上面considerNotify方法中有这么个判断条件:
if (observer.mLastVersion >= mVersion) {
return;
}
如果能在调用onChange方法之前使if条件命中,那么就可以避免粘包事件。等到绑定完observer之后,再次更新数据时候,setValue中会调用mVersion++,更新mVersion的值,这个时候if条件就不会命中了,那么就可以正常收发数据,而躲过observe绑定订阅之前的数据
此处利用反射,修改observer.mLastVersion的值:
public class LiveDataBusX {
//存放订阅者
private Map<String, BusMutableLiveData<Object>> bus;
private static LiveDataBusX liveDataBus = new LiveDataBusX();
private LiveDataBusX() {
bus = new HashMap<>();
}
public static LiveDataBusX getInstance() {
return liveDataBus;
}
//注册订阅者,(存入map) Hook前用MutableLiveData
public synchronized <T> BusMutableLiveData<T> with(String key, Class<T> type){
if(!bus.containsKey(key)){
bus.put(key,new BusMutableLiveData<Object>());
}
return (BusMutableLiveData<T>) bus.get(key);
}
public static class BusMutableLiveData<T> extends MutableLiveData<T> {
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
super.observe(owner, observer);
hook(observer);
}
//在这里去改变onChange的流程
private void hook(Observer<? super T> observer) {
try {
//1.得到mLastVersion
//获取到LiveData的类中的mObservers对象
Class<LiveData> liveDataClass = LiveData.class;
Field mObserversField = liveDataClass.getDeclaredField("mObservers");
mObserversField.setAccessible(true);
//获取到这个成员变量的对象
Object mObserversObject = mObserversField.get(this);
//得到map对应的class对象
Class<?> mObserversClass = mObserversObject.getClass();
//获取到mObservers对象的get方法
Method get = mObserversClass.getDeclaredMethod("get", Object.class);
get.setAccessible(true);
//执行get方法
Object invokeEntry=get.invoke(mObserversObject,observer);
//定义一个空的对象
Object observerWraper=null;
if(invokeEntry!=null && invokeEntry instanceof Map.Entry){
observerWraper=((Map.Entry)invokeEntry).getValue();
}
if(observerWraper==null){
throw new NullPointerException("observerWraper is null");
}
//得到ObserverWrapper的类对象 编译擦除问题会引起多态冲突所以用getSuperclass
Class<?> superclass = observerWraper.getClass().getSuperclass();
Field mLastVersion = superclass.getDeclaredField("mLastVersion");
mLastVersion.setAccessible(true);
//2.得到mVersion
Field mVersion = liveDataClass.getDeclaredField("mVersion");
mVersion.setAccessible(true);
//3.把mVersion的数据填入到mLastVersion中
Object mVersionValue=mVersion.get(this);
mLastVersion.set(observerWraper,mVersionValue);
}catch (Exception e){
e.printStackTrace();
}
}
}
}
使用方式:
修改之前MainActivity和TestLiveDataBusActivity的使用方式:
//MainActivity.java
new Thread(){
@Override
public void run() {
for (int i = 0; i < 10; i++) {
//发送消息
LiveDataBusX.getInstance().with("data", String.class).postValue("xxx");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
//TestLiveDataBusActivity.java
LiveDataBusX.getInstance().with("data", String.class)
.observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
if(s!=null)
Toast.makeText(TestLiveDataBusActivity.this, s, Toast.LENGTH_SHORT).show();
}
});
这样再次使用,就会发现,在TestLiveDataBusActivity中,调用observe方法之前,LiveData更新的消息没有回调onChange方法,只收到了observe之后的消息更新。
这样LiveData粘包问题就搞定了。