-
LiveData
2021-01-19 18:02:24JetPacket LiveData 本文主要介绍两方面的内容 LiveData简单使用 LiveData的粘包事件原因以及处理方式 LiveData简介 LiveData是可以在给定生命周期内观察到的数据持有者类。这意味着Observer可以配对添加...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使用
这里先创建一个ViewModelpublic 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粘包问题就搞定了。 -
LIvedata
2019-01-03 10:42:14LiveData是一个可被观察的数据持有者类。与常规的Observable不同,LiveData能意识到应用程序组件的生命周期变化,这意味着它能遵守Activity、Fragment、Service等组件的生命周期。这种意识确保LiveData只更新处于...LiveData是一个可被观察的数据持有者类。与常规的Observable不同,LiveData能意识到应用程序组件的生命周期变化,这意味着它能遵守Activity、Fragment、Service等组件的生命周期。这种意识确保LiveData只更新处于活跃状态的应用程序组件Observe。
LiveData优点:
一,保证数据与界面的实时更新
LiveData
采用了观察者模式设计,其中LiveData
是被观察者,当数据发生变化时会通知观察者进行数据更新。通过这点,可以确保数据和界面的实时性。二,有效避免内存泄漏
这是因为
LiveData
能够感知到组件的生命周期,当组件状态处于DESTROYED
状态时,观察者对象会被remove
。三,
Activity/Fragment
销毁掉时不会引起崩溃这是因为组件处于非激活状态时,在界面不会收到来自
LiveData
的数据变化通知。这样规避了很多因为页面销毁之后,修改UI导致的crash
。四,不需要手动处理生命周期
LiveData
能够感知组件的生命周期,所以设置LiveData
组件的生命周期状态。五,始终能够保持最新数据
生命周期从非活跃状态切换到活跃状态的时候,能够实时的接收最新的数据。
六,能够应对配置更改
由于
LiveData
保存数据的时候,组件和数据是分离的,所以在配置更改(如横竖屏切换等)的时候,即便组件被重新创建,因为数据还保存在LiveData
中,这样也能够做到实时的更新。七,资源共享
单例模式扩展
LiveData
对象并包装成系统服务,以便在应用程序中进行共享,需要该资源的只需要观察LiveData
即可。LiveData的数据更新
LiveData
的数据更新有两种方式,第一种就是使用setValue
的方式只能在主线程也就是UI线程里面调用,另外一种就是postValue
的方式可以在主线程或者子线程里面调用MutabeLiveData
:继承了LiveData
,LiveData
是一个抽象类不能直接使用,在子类里面重写了postValue
和setValue
两个方法;合并多个LiveData源
MediatorLiveData是LiveData的一个子类,帮助您合并多个LiveData源。 在任何原始LiveData源对象改变后,MediatorLiveData对象的Observer会被触发。
LiveData转换
您可能想对存储在LiveData对象中的值进行更改后再分配给观察者,或者您可能需要根据另一个LiveData实例返回不同的LiveData实例,
Transformations
类,它包括支持这些场景
-
scrapy框架
-
常用类库之Java.text.SimpleDateFormat
-
Python获取Websocket接口的数据
-
pyechart数据可视化
-
python寻找摄像头参数
-
awt的一个图片匹配算法系统.zip
-
示例数据下载-省会连线.csv
-
TLP-Task13学习笔记
-
单元测试UnitTest+Pytest【Selenium3】
-
centos7.2安装php7.2
-
【数据分析-随到随学】Python数据获取
-
webgl室内3d场景.zip
-
android笔试面试和实战课程
-
异常
-
将人从图像中抠取出来
-
python数据分析基础
-
SIMATIC NET_ 工业以太网交换机 SCALANCE X-200.pdf
-
火绒安全软件 v5.0.49.1
-
微信支付2021系列之扫码支付一学就会java版
-
使用PHP实现WEB网站登陆后台编写