1.liveData的基本使用

1.1添加依赖

在build.gradle(app)中添加依赖

dependencies {implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0-rc01"implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.5.0-rc01"
}

自定义viewModel,持有LiveData

class MessageViewModel:ViewModel() {val message : MutableLiveData<String> by lazy {MutableLiveData<String>()}
}

MainActivity中代码如下

class MainActivity : AppCompatActivity() {private lateinit var  binding:ActivityMainBindingcompanion object{@JvmFieldvar  viewModel = MessageViewModel()}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)binding = ActivityMainBinding.inflate(layoutInflater)setContentView(binding.root)initView()}private fun initView(){with(binding){//观察者var count = 0val observer = Observer<String>{Log.d("debug", it)tvMessage.text = it}//添加观察者viewModel.message.observe(this@MainActivity,observer)//在主线程中更新内容sendMessageInMainThread.setOnClickListener {viewModel.message.value = "在主线程中更新内容---$count"}//在子线程中更新内容sendMessageInSonThread.setOnClickListener {Thread{viewModel.message.postValue("在子线程中更新内容---$count")count++}.run()}}}
}

2.LiveData怎么添加观察者

类图如下

事件分发的时序图如下,

先找到添加观察者的入口
viewModel.message.observe(this@MainActivity,observer)
点击进入LiveData的observe()中

 @MainThreadpublic void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {//检查是否在主线程中调用observe(),如果不是抛出异常assertMainThread("observe");//检查Activity/Fragment的状态,如果已经DESTROYED,则直接退出,不用继续往下走if (owner.getLifecycle().getCurrentState() == DESTROYED) {// ignorereturn;}//这里创建一个带生命周期的观察者对象LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);//将这个观察者放入Map中,根据返回值,判断这个带生命周期的观察者是否和多个被观察者绑定,//如果和多个被观察者绑定则抛出异常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;}//这里获取Lifecycle的唯一实现类LifecycleRegistry的实例,将这个带生命周期的观察者添加进去owner.getLifecycle().addObserver(wrapper);}

点击addObserver(),进入LifecycleRegistry的方法中

@Overridepublic void addObserver(@NonNull LifecycleObserver observer) {enforceMainThreadIfNeeded("addObserver");//初始化刚加入的LifecycleBoundObserver对象的状态,默认为INITIALIZEDState initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;//同时使用带生命周期的observer和初始化状态生成一个带状态和生命周期的observer,ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);//检查这个observer是否存在ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);if (previous != null) {return;}LifecycleOwner lifecycleOwner = mLifecycleOwner.get();//检查宿主是否被销毁了if (lifecycleOwner == null) {// it is null we should be destroyed. Fallback quicklyreturn;}//重入标志,boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;//计算observer要到达的状态,这里使用状态机State targetState = calculateTargetState(observer);mAddingObserverCounter++;//进行状态同步,和targetState进行比较while ((statefulObserver.mState.compareTo(targetState) < 0&& mObserverMap.contains(observer))) {//将当前这个statefulObserver的状态压入栈中, //private ArrayList<State> mParentStates = new ArrayList<>();//这是个ArrayList线程不安全pushParentState(statefulObserver.mState);final Event event = Event.upFrom(statefulObserver.mState);if (event == null) {throw new IllegalStateException("no event up from " + statefulObserver.mState);}//进行事件分发statefulObserver.dispatchEvent(lifecycleOwner, event);//popParentState();// mState / subling may have been changed recalculate//更新targetStatetargetState = calculateTargetState(observer);}if (!isReentrance) {// we do sync only on the top level.sync();}mAddingObserverCounter--;}

进入同步

// happens only on the top of stack (never in reentrance),// so it doesn't have to take in account parentsprivate void sync() {LifecycleOwner lifecycleOwner = mLifecycleOwner.get();if (lifecycleOwner == null) {throw new IllegalStateException("LifecycleOwner of this LifecycleRegistry is already"+ "garbage collected. It is too late to change lifecycle state.");}while (!isSynced()) {//这里和moveToState()的mNewEventOccurred 一致mNewEventOccurred = false;// no need to check eldest for nullability, because isSynced does it for us.//无须检查 eldest的是否为空,isSynced()中已经帮我们做了//LifecycleRegister的状态和当前栈中最底层的observer的状态比较if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {//调整LifecycleOwner的state,降级backwardPass(lifecycleOwner);}//LifecycleRegister的状态和当前栈中最顶层的observer的状态比较Map.Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();if (!mNewEventOccurred && newest != null&& mState.compareTo(newest.getValue().mState) > 0) {//将lifecycleOwner的状态升级forwardPass(lifecycleOwner);}}mNewEventOccurred = false;}

关于这个状态的升级和降级和Activity的生命周期相关,下面代码是Lifecycle中的具体实现

   @NonNullpublic State getTargetState() {switch (this) {case ON_CREATE:case ON_STOP:return State.CREATED;case ON_START:case ON_PAUSE:return State.STARTED;case ON_RESUME:return State.RESUMED;case ON_DESTROY:return State.DESTROYED;case ON_ANY:break;}throw new IllegalArgumentException(this + " has no target state");}

用图表示为:

 private boolean isSynced() {if (mObserverMap.size() == 0) {return true;}State eldestObserverState = mObserverMap.eldest().getValue().mState;State newestObserverState = mObserverMap.newest().getValue().mState;return eldestObserverState == newestObserverState && mState == newestObserverState;}

3.当数据发生变化,怎么通知观察者

viewModel.message.value = "在主线程中更新内容---$count"
从setValue这里进入,发现使用了父类LiveData的方法

 @Overridepublic void setValue(T value) {super.setValue(value);}

进入LiveData中setValue(T value)

     @MainThreadprotected void setValue(T value) {assertMainThread("setValue");//将版本+1,初始值为 0mVersion++;mData = value;//如果有活跃的观察者,则分配值给他们dispatchingValue(null);}

继续跟踪进入 dispatchingValue()

    @SuppressWarnings("WeakerAccess") /* synthetic access */void dispatchingValue(@Nullable ObserverWrapper initiator) {//其中mSispatchingValue ,表示是否正在分发值if (mDispatchingValue) {mDispatchInvalidated = true;return;}mDispatchingValue = true;do {//这里做了个循环,mDispatchInvalidated 表示是否同时有其他线程调用分发mDispatchInvalidated = false;if (initiator != null) {considerNotify(initiator);initiator = null;} else {for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {considerNotify(iterator.next().getValue());//如果有其他线程也在分发数据,立即停止分发,跳出循环if (mDispatchInvalidated) {break;}}}} while (mDispatchInvalidated);mDispatchingValue = false;}

进入到considerNotify()

    @SuppressWarnings("unchecked")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);}

4.LifeCycleOwner生命周期发生变化时,怎么及时通知观察者

这里Google官方用了一个比较奇妙的方法,因为Fragment的生命周期会跟随Activity的生命周期发生变化,
所以Google使用了一个无界面ReportFragment来感知生命周期的变化,当生命周期发生变化时,分发事件
在ComponentActivity的onCreate()方法中

    @Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {// Restore the Saved State first so that it is available to// OnContextAvailableListener instancesmSavedStateRegistryController.performRestore(savedInstanceState);mContextAwareHelper.dispatchOnContextAvailable(this);super.onCreate(savedInstanceState);mActivityResultRegistry.onRestoreInstanceState(savedInstanceState);//这里进行注入ReportFragment.injectIfNeededIn(this);if (mContentLayoutId != 0) {setContentView(mContentLayoutId);}}

进入ReportFragment的injectIfNeededIn()中

public static void injectIfNeededIn(Activity activity) {if (Build.VERSION.SDK_INT >= 29) {// 在 API 29+ 上,我们可以直接注册正确的生命周期回调LifecycleCallbacks.registerIn(activity);}/**在 API 29 之前并保持与旧版本的 ProcessLifecycleOwner 的兼容性(更新生命周期运行时可能不会更新,并且需要支持不从支持 lib 扩展的 FragmentActivity 的活动),使用框架片段来获得正确的生命周期事件的时间安排*/android.app.FragmentManager manager = activity.getFragmentManager();if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {manager.beginTransaction().add(new ReportFragment(), REPORT_FRAGMENT_TAG).commit();// Hopefully, we are the first to make a transaction.manager.executePendingTransactions();}}

最终调用的是dispatch()

@SuppressWarnings("deprecation")static void dispatch(@NonNull Activity activity, @NonNull Lifecycle.Event event) {if (activity instanceof LifecycleRegistryOwner) {((LifecycleRegistryOwner) activity).getLifecycle().handleLifecycleEvent(event);return;}if (activity instanceof LifecycleOwner) {Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();if (lifecycle instanceof LifecycleRegistry) {((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);}}}

handleLifecycleEvent是属于LifecycleRegistry,那么终于都连起来了,
进入到handleLifeCycleEvent中

public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {enforceMainThreadIfNeeded("handleLifecycleEvent");moveToState(event.getTargetState());}//进行状态转移
private void moveToState(State next) {if (mState == next) {return;}mState = next;if (mHandlingEvent || mAddingObserverCounter != 0) {mNewEventOccurred = true;// we will figure out what to do on upper level.return;}mHandlingEvent = true;//同步所有观察者,并进行事件分发sync();mHandlingEvent = false;}

5.怎么解决LiveData的黏性事件

粘性事件的定义是什么?
即发射的事件如果早于注册,那么注册之后依然可以接收到的事件称为粘性事件,举个栗子,比如我在2022年订阅了一份广州日报,但是你还给我推送2019年的报纸,那就不厚道了,参考了博主我星空的文章:http://t.csdn.cn/w35CO看下源码,主要的原因是

  @SuppressWarnings("unchecked")private void considerNotify(ObserverWrapper observer) {//1if (!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.//2if (!observer.shouldBeActive()) {observer.activeStateChanged(false);return;}//一般事件流程 :new Observe(mVersion=-1)-> 注册观察者(mLastVersion=-1)-> setValue(mVersion++) //粘性事件的流程 :new Observe(mVersion=-1)-> setValue(mVersion++) ->注册观察者(mLastVersion=-1)//此时 mLastVersion=-1 , mVersion=0 ,未触发拦截导致首次注册时会触发接口回调造成粘性事件if (observer.mLastVersion >= mVersion) {return;}observer.mLastVersion = mVersion;observer.mObserver.onChanged((T) mData);}

解决方法是第一次进行拦截,不让livedate进行事件分发,注释1 和注释2 处的代码涉及到Framework层的代码,不好动,只能在第mLaseVersion 和mVersion上动手脚,在注册观察者时,通过反射修改mLastVersion的值,使得mLastVersion 和mVersion的值相等,那么就可以直接返回,不进行事件分发

class NonStickyMutableLiveData<T> : MutableLiveData<T>() {private var stickFlag = trueoverride fun observe(owner: LifecycleOwner, observer: Observer<in T>) {super.observe(owner, observer)if (stickFlag) {hook(observer)}}private fun hook(observer: Observer<in T>) {try {val liveDataClass = LiveData::class.javaval mObserversField = liveDataClass.getDeclaredField("mObservers")mObserversField.isAccessible = trueval mObserversObject = mObserversField[this]//得到map对应的class对象val mObserversClass: Class<*> = mObserversObject.javaClass//获取到mObserversClass对象的get()val get = mObserversClass.getDeclaredMethod("get", Any::class.java)get.isAccessible = true//执行get方法val invokeEntry = get.invoke(mObserversObject, observer)//定义一个空对象var observerWrapper: Any? = nullif (invokeEntry != null && invokeEntry is Map.Entry<*, *>) {observerWrapper = invokeEntry.value}if (observerWrapper == null) {throw NullPointerException("observerWrapper is null")}//得到ObserverWrapper的类对象,编译擦除问题会引起多态冲突所以用getSuperClassval superClass: Class<*> = observerWrapper.javaClass.superclassval mLastVersion = superClass.getDeclaredField("mLastVersion")mLastVersion.isAccessible = true//得到mversionval mVersion = liveDataClass.getDeclaredField("mVersion")mVersion.isAccessible = true//将mVersion的值填入到mLastVersionval mVersionValue = mVersion[this]mLastVersion[observerWrapper] = mVersionValuestickFlag = false} catch (e: Exception) {e.printStackTrace()}}
}

LiveData的基本使用和原理解析相关推荐

  1. Jetpack Room 使用及原理解析

    深入学习 Jetpack 系列的 Android Architecture Components 中的一些列组件,记录一下学习过程,本文是 Room 的使用及原理解析,通过一个实际的例子,来体验 Ro ...

  2. Spark Shuffle原理解析

    Spark Shuffle原理解析 一:到底什么是Shuffle? Shuffle中文翻译为"洗牌",需要Shuffle的关键性原因是某种具有共同特征的数据需要最终汇聚到一个计算节 ...

  3. 秋色园QBlog技术原理解析:性能优化篇:用户和文章计数器方案(十七)

    2019独角兽企业重金招聘Python工程师标准>>> 上节概要: 上节 秋色园QBlog技术原理解析:性能优化篇:access的并发极限及分库分散并发方案(十六)  中, 介绍了 ...

  4. Tomcat 架构原理解析到架构设计借鉴

    ‍ 点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 Tomcat 架构原理解析到架构设计借鉴 Tomcat 发展这 ...

  5. 秋色园QBlog技术原理解析:性能优化篇:数据库文章表分表及分库减压方案(十五)...

    文章回顾: 1: 秋色园QBlog技术原理解析:开篇:整体认识(一) --介绍整体文件夹和文件的作用 2: 秋色园QBlog技术原理解析:认识整站处理流程(二) --介绍秋色园业务处理流程 3: 秋色 ...

  6. CSS实现元素居中原理解析

    原文:CSS实现元素居中原理解析 在 CSS 中要设置元素水平垂直居中是一个非常常见的需求了.但就是这样一个从理论上来看似乎实现起来极其简单的,在实践中,它往往难住了很多人. 让元素水平居中相对比较简 ...

  7. 秋色园QBlog技术原理解析:Web之页面处理-内容填充(八)

    文章回顾: 1: 秋色园QBlog技术原理解析:开篇:整体认识(一) --介绍整体文件夹和文件的作用 2: 秋色园QBlog技术原理解析:认识整站处理流程(二) --介绍秋色园业务处理流程 3: 秋色 ...

  8. 秋色园QBlog技术原理解析:UrlRewrite之无后缀URL原理(三)

    文章回顾: 1: 秋色园QBlog技术原理解析:开篇:整体认识(一) --介绍整体文件夹和文件的作用 2: 秋色园QBlog技术原理解析:认识整站处理流程(二) --介绍秋色园业务处理流程 本节,将从 ...

  9. Android之Butterknife原理解析

    转载请标明出处:[顾林海的博客] 个人开发的微信小程序,目前功能是书籍推荐,后续会完善一些新功能,希望大家多多支持! ##前言 Butterknife是一个专注于Android系统的View注入框架, ...

最新文章

  1. Bhaskar Chowdhury: Kernel build failed ...SPHINX extension error
  2. HTML中字体的垂直排列
  3. java单链表 提供增删改查_java实现单链表增删改查的实例代码详解
  4. spark 设置主类_最近Kafka这么火,聊一聊Kafka:Kafka与Spark的集成
  5. java 字符串编程题_Java编程题——在一个字符串中查找第一个非重复的字符
  6. php fsockopen 异步,异步执行PHP任务fsockopen的干货
  7. CI中创建你自己的类库
  8. Beginning WF 4.0翻译——第一章(创建一个简单的工作流)续二
  9. Android入门项目(校园软件)
  10. 使用 URLDecoder 和 URLEncoder 对中文字符进行编码和解码
  11. BlockUI详细用法
  12. 软件工程案例-仓库管理系统简单版
  13. . java.lang.IllegalArgumentException: requirement failed: Can only call getServletHandlers on a runn
  14. 人脸识别: 人脸数据集大全
  15. 在腾讯这一年,坚守初心持续单纯!
  16. Springboot 自定义全局异常处理
  17. 使用echarts实现3D地图和需要注意的点
  18. WinFrom内嵌chrome浏览器
  19. ⭐全网最强Java基础总结 ⭐,质量不行你直接拉黑我就行
  20. 虚拟化存储的方法有哪几种

热门文章

  1. 浪漫侧影 ( 题解 )
  2. 瑞萨单片机iap串口升级boot程序与app程序合并的工程构建-学习记录
  3. python如何计算成绩平方根_python 使用二分法计算平方根
  4. ESP8266 Ticker学习
  5. “云界十年”——第十届中国云计算大会举行
  6. 手把手QQ机器人制作教程,根据官方接口进行开发,基于Python语言制作的详细教程(更新中)
  7. 使用proteus仿真验证基尔霍夫定律
  8. IDA Pro 4.9.0.863 Advanced Full with SDK
  9. 我自己制作的导航页网站,源码免费分享~
  10. 46、微信-群聊列表