LiveData源码分析

1.在上一篇文章中介绍了LiveData的简单使用,可以查看LiveData简单使用_niuyongzhi的博客-CSDN博客

源码分析:

也可以分成两部分来看,一部分是注册observe源码,另一部分是setValue的源码。

先看Observe注册监听的方法。

1)先看liveData.observe()

 MutableLiveData<Person> liveData = new MutableLiveData();liveData.observe(this, new Observer<Person>() {@Overridepublic void onChanged(Person person) {ageTv.setText(String.valueOf(person.age));nameTv.setText(person.name);}});
    private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =new SafeIterableMap<>();@MainThreadpublic void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {if (owner.getLifecycle().getCurrentState() == DESTROYED) {return;}//定义了一个Observer的包装类,用于数据变化时的回调。LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);//将wrapper存入一个HashMap中,ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);....//向LifeCycle注册监听,这样wrapper就可以感知Activity声明周期变化。owner.getLifecycle().addObserver(wrapper);}

 看下这个LifecycleBoundObserver 类。

 class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {@NonNullfinal LifecycleOwner mOwner;LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {super(observer);mOwner = owner;}@Overrideboolean shouldBeActive() {return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);}//在收到Activity生命周期变化时,会回调这个方法。@Overridepublic void onStateChanged(@NonNull LifecycleOwner source,@NonNull Lifecycle.Event event) {//拿到当前的状态Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();if (currentState == DESTROYED) {//如果Activity的状态是销毁状态,则会从集合中移除注册的observer,防止内存泄露removeObserver(mObserver);return;}//状态同步Lifecycle.State prevState = null;while (prevState != currentState) {prevState = currentState;activeStateChanged(shouldBeActive());currentState = mOwner.getLifecycle().getCurrentState();}}@Overrideboolean isAttachedTo(LifecycleOwner owner) {return mOwner == owner;}@Overridevoid detachObserver() {mOwner.getLifecycle().removeObserver(this);}}

 看activeStateChanged()方法 更新状态。

 void activeStateChanged(boolean newActive) {if (newActive == mActive) {return;}// immediately set active state, so we'd never dispatch anything to inactive// ownermActive = newActive;changeActiveCounter(mActive ? 1 : -1);if (mActive) {dispatchingValue(this);}}

    2)在看setValue中做了啥

     //看setValue的执行逻辑protected void setValue(T value) {//不是运行在主线程,抛异常assertMainThread("setValue");//版本控制,每调用一次setValue,version加1mVersion++;mData = value;//数据分发,注意这里传的参数是nulldispatchingValue(null);}

看dispatchingValue方法

 private void dispatchingValue(@Nullable ObserverWrapper initiator) {if (mDispatchingValue) {mDispatchInvalidated = true;return;}mDispatchingValue = true;do {mDispatchInvalidated = false;if (initiator != null) {considerNotify(initiator);initiator = null;} else {//由于上面传过来的参数是null,所以会执行这个循环遍历mObservers//而mObservers就保存了向liveData添加的observerfor (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator =mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {considerNotify(iterator.next().getValue());if (mDispatchInvalidated) {break;}}}} while (mDispatchInvalidated);mDispatchingValue = false;}

由于上面参数initiator传递过来的是null,所以会执行到for循环中的     considerNotify(iterator.next().getValue());  iterator.next().getValue()拿到的就是ObserverWrapper的实例。

再看considerNotify方法()

 private void considerNotify(ObserverWrapper observer) {//如果观察在没有处于活跃状态,则不会受到更新的数据if (!observer.mActive) {return;}//这个判断是LifeCycleOwner的状态是否处于活跃状态if (!observer.shouldBeActive()) {observer.activeStateChanged(false);return;}//如果Observer中的版本已经是最新的,则不会更新if (observer.mLastVersion >= mVersion) {return;}observer.mLastVersion = mVersion;//调用observer中的回调方法。//observer就是上面创建的LifecycleBoundObserver的实例//mObserver就是添加的观察者observer.mObserver.onChanged((T) mData);}

 if (!observer.mActive) {
            return;
        }

这行代码,就控制了,不是活跃状态的观察者,不会去更新数据,保证处于前台的Activity中的LiveData,会刷新UI。

2.LiveData的粘性事件:

在第一个Activity中调用 liveData.setValue("main");已经注册的Observer能够收到消息。
当跳转到第二个Activity向第一个Activity中的LiveData添加Observer时,也会收到之前发送的消息。
这样的情况就是粘性事件。
正常的流程是  new LiveData----addObserver---setValue--收到消息
粘性事件的流程是 new LiveData---setValue-----addObserver--收到消息。
LiveData的粘性事件,并不是他的bug,而是出于某种业务需要才这样做到的,就是为了确保数据更新后,即使打开新的Activity也能够显示最新的数据。如果不期望这种效果,由于目前LiveData还没有提供这样的Api,所以得需要我们自己来实现。

LiveData出现粘性事件的源码分析。

由于第二个Activity也是实现了LifecycleOwner,也会调用ReportFragment的dispatch(Lifecycle.Event event)方法

private void dispatch(Lifecycle.Event event) {if (activity instanceof LifecycleOwner) {Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();if (lifecycle instanceof LifecycleRegistry) {((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);}}
}

看过LifeCycle源码分析的,对后面的执行流程应该很熟悉。

 static class ObserverWithState {State mState;GenericLifecycleObserver mLifecycleObserver;ObserverWithState(LifecycleObserver observer, State initialState) {mLifecycleObserver = Lifecycling.getCallback(observer);mState = initialState;}void dispatchEvent(LifecycleOwner owner, Event event) {State newState = getStateAfter(event);mState = min(mState, newState);mLifecycleObserver.onStateChanged(owner, event);mState = newState;}}

直接看到这里mLifecycleObserver是谁的实例?看Lifecycling.getCallback(observer);
在LifeCycle的回调中返回的是ReflectiveGenericLifecycleObserver的实例。
但是在LiveData中mLifecycleObserver是LifecycleBoundObserver的实例,实现了GenericLifecycleObserver接口。
 在调用LiveData.Observer()创建了LifecycleBoundObserver的实例。

 static GenericLifecycleObserver getCallback(Object object) {if (object instanceof FullLifecycleObserver) {return new FullLifecycleObserverAdapter((FullLifecycleObserver) object);}//LiveData中传进来的是LifecycleBoundObserver//所以在这里就return了if (object instanceof GenericLifecycleObserver) {return (GenericLifecycleObserver) object;}.......return new ReflectiveGenericLifecycleObserver(object);}

看LiveData.Observer()源码,创建了LifecycleBoundObserver对象,并作为观察者,添加到了LifeCycle中

public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);owner.getLifecycle().addObserver(wrapper);
}

在addObserver中,用ObserverWithState对LifecycleBoundObserver进行了一层封装。

 public void addObserver(@NonNull LifecycleObserver observer) {State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
}

综上代码,可以知道  mLifecycleObserver.onStateChanged(owner, event);
调用的是LifecycleBoundObserver的onStateChanged方法。

public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {//如果当前Activity是Destroy的,则回收Observer,防止发送内存泄露if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {removeObserver(mObserver);return;}activeStateChanged(shouldBeActive());}
 //删除的LiveData中该Activity(LifecycleOwner)添加的observer,//在LiveData.Observer时会传入LifecycleOwner,public void removeObserver(@NonNull final Observer<T> observer) {assertMainThread("removeObserver");ObserverWrapper removed = mObservers.remove(observer);if (removed == null) {return;}removed.detachObserver();removed.activeStateChanged(false);}
activeStateChanged(shouldBeActive());
//shouldBeActive判断是Activity是否是线上状态。boolean shouldBeActive() {return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
//在第二个Activity启动后,这个newActive传过来的是true
void activeStateChanged(boolean newActive) {//mActive默认是false,newActive是trueif (newActive == mActive) {return;}mActive = newActive;boolean wasInactive = LiveData.this.mActiveCount == 0;//记录avtiveCount,如果活跃加1否则减1LiveData.this.mActiveCount += mActive ? 1 : -1;if (wasInactive && mActive) {onActive();}if (LiveData.this.mActiveCount == 0 && !mActive) {onInactive();}if (mActive) {dispatchingValue(this);}
}
//dispatchingValue把this传进来了,所以下面代码会执行if判断的第一个分支private void dispatchingValue(@Nullable ObserverWrapper initiator) {if (mDispatchingValue) {mDispatchInvalidated = true;return;}mDispatchingValue = true;do {mDispatchInvalidated = false;//initiator不是null执行这里if (initiator != null) {considerNotify(initiator);initiator = null;} else {for (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator =mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {considerNotify(iterator.next().getValue());if (mDispatchInvalidated) {break;}}}} while (mDispatchInvalidated);mDispatchingValue = false;}
 private void considerNotify(ObserverWrapper observer) {//observer.mActive 为trueif (!observer.mActive) {return;}//observer.shouldBeActive()为trueif (!observer.shouldBeActive()) {observer.activeStateChanged(false);return;}//mVersion是LiveData的变量,会大于0//observer.mLastVersion初始值是0,//所以这个分支判断也不会进来if (observer.mLastVersion >= mVersion) {return;}//版本同步observer.mLastVersion = mVersion;//这行代码,就会调用observer的onChange方法observer.mObserver.onChanged((T) mData);}

所以在第二个Activity中添加的observer就收到了第一个Activity发送的消息。
 这就是LiveData粘性事件的源码执行原理。
 如果想要消除这种粘性事件,通过上面的代码分析,我们可以修改添加的Observer的mLastVersion值,
 使它在初始化时就和LiveData中的mVersion一致,就不会出现粘性事件。

3. liveData.observeForever(observer)

 liveData.observeForever 是一个和Activity声明周期无关的消息订阅与发送的方法

public void observeForever(@NonNull Observer<T> observer) {AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);if (existing != null) {return;}//这个参数是truewrapper.activeStateChanged(true);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/89408.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis实现Session持久化

Redis实现Session持久化 1. 前言 直接使用Session存储用户登录信息&#xff0c;此时的会话信息是存储在内中的&#xff0c;只要项目重启存储的Session信息就会丢失。而使用Redis存储Session的话就不会存在这种情况&#xff0c;即使项目重启也并不影响&#xff0c;也无需用户重…

GIT提示Another git process seems to be running in this repository

解决方法 1、进入项目里面的.git文件里面找到index.lock删除即可。

掷骰子的多线程应用程序2基于互斥量的线程同步(复现《Qt C++6.0》)

说明&#xff1a;在复现过程中出现两点问题&#xff08;1&#xff09;run()函数中对m_diceValued的赋值&#xff08;2&#xff09;do_timeOut()函数中没有对m_seq、m_diceValued进行定义。修改后的复现程序如下所示&#xff1a; 主线程&#xff1a; .h #pragma once#include…

PostgreSQL 查询某个属性相同内容出现的次数

查询某个数据库表属性 name 相同内容出现出现的次数&#xff0c;并按次数从大到小排序 SELECT name, COUNT(*) AS count FROM your_table GROUP BY name ORDER BY count DESC;示例 select project_id, COUNT(*) AS count from app_ads_positions group by project_id order b…

民安智库(专业市场调查公司)家居行业消费者调查如何做?

随着人们生活水平的提高&#xff0c;家居行业的发展日益蓬勃。在家居行业竞争激烈的市场环境下&#xff0c;了解消费者的需求和喜好至关重要。为了更好地了解家居消费者的需求和习惯&#xff0c;为家居品牌方提供有力的市场支持&#xff0c;民安智库通过本文介绍家居行业消费者…

mysql Your password does not satisfy the current policy requirements

在修改密码时遇到 Your password does not satisfy the current policy requirements 原因&#xff1a;您的密码不符合当前策略要求&#xff0c;最好是把密码设置成复杂的&#xff0c;包括字母大小写、数字、特殊字符。 如果你还是先把数据库密码改简单&#xff0c;比如你本地…

Redis 集合操作实战(全)

目录 SADD 插入集合 SCARD 取元素数量 SPOP 随机移除元素 SREM 移除多个元素 SMOVE 移动元素到别的集合 SMEMBERS 取所有成员 SRANDMEMBER 取指定数量元素 SISMEMBER 判断元素是否存在 SUNION 多集合求并集 SUNIONSTORE 多集合求并集&#xff08;存储&#xff09; S…

vue点击按钮收缩菜单

问题描述 VUE菜单有一个BUG&#xff0c;当我们点击其它按钮或者首页的时候&#xff0c;已经展示的一级菜单是不会自动收缩的。这个问题也导致很多开发者把一级菜单都换成了二级菜单。 错误展示 错误的效果请看下图。 解决方法 1、寻找菜单文件 因为我使用的是ruoyi的前端框…

Spring Controller内存马

获取当前上下文运行环境 getCurrentWebApplicationContext WebApplicationContext context ContextLoader.getCurrentWebApplicationContext(); 在SpringMVC环境下获取到的是一个XmlWebApplicationContext类型的Root WebApplicationContext&#xff1a; 在Spring MVC环境中…

可信执行环境(Tee)入门综述

SoK: Hardware-supported Trusted Execution Environments [ArXiv22] 摘要引言贡献 范围系统和威胁模型系统模型威胁模型共存飞地对手无特权软件对手系统软件对手启动对手外围对手结构对手侵入性对手 关于侧信道攻击的一点注记 VERIFIABLE LAUNCH信任根&#xff08;RTM&#xf…

8月最新修正版风车IM即时聊天通讯源码+搭建教程

8月最新修正版风车IM即时聊天通讯源码搭建教程。风车 IM没啥好说的很多人在找,IM的天花板了,知道的在找的都知道它的价值,开版好像就要29999,后端加密已解,可自己再加密,可反编译出后端项目源码,已增加启动后端需要google auth双重验证,pc端 web端 wap端 android端 ios端 都有 …

【Java 进阶篇】数据定义语言(DDL)详解

数据定义语言&#xff08;DDL&#xff09;是SQL&#xff08;结构化查询语言&#xff09;的一部分&#xff0c;它用于定义、管理和控制数据库的结构和元素。DDL允许数据库管理员、开发人员和其他用户创建、修改和删除数据库对象&#xff0c;如表、索引、视图等。在本文中&#x…

100万级连接,石墨文档WebSocket网关如何架构?

说在前面 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;很多小伙伴拿到一线互联网企业如阿里、网易、有赞、希音、百度、滴滴的面试资格。 最近&#xff0c;尼恩指导一个小伙伴简历&#xff0c;写了一个《高并发网关项目》&#xff0c;此项目帮这个小伙拿到 字节/阿里/…

【量化】量化原理浅析

前言 模型在端侧运行时&#xff0c;会追求模型保持原有精度的同时&#xff0c;让模型的运行速度更快。基本方向为模型压缩和加速&#xff0c;着力于减少网络参数量、降低计算复杂度。可通过以下方式实现&#xff1a; 针对网络结构本身进行改进&#xff0c;常用的3x3的卷积的叠加…

Docker-如何获取docker官网x86、ARM、AMD等不同架构下的镜像资源

文章目录 一、概要二、资源准备三、环境准备1、环境安装2、服务器设置代理3、注册docker账号4、配置docker源 四、查找资源1、服务器设置代理2、配置拉取账号3、查找对应的镜像4、查找不同版本镜像拉取 小结 一、概要 开发过程中经常会使用到一些开源的资源&#xff0c;比如经…

基于体系结构-架构真题2022(四十一)

给定关系模式R&#xff08;U,F&#xff09;&#xff0c;其中U为属性集&#xff0c;F是U上的一组函数依赖&#xff0c;那么函数依赖的公理系统中分解规则是指&#xff08;&#xff09;为F所蕴含。 解析&#xff1a; 伪传递是x到y&#xff0c;wy到z&#xff0c;则xw到z 传递是z…

CISSP学习笔记:通过原则和策略的安全治理

#第一章 通过原则和策略的安全治理 1.1 理解和应用机密性、完整性和可用性的 安全的主要目标&#xff0c;CIA三元组 机密性、完整性和可用性&#xff0c;每条原则的重要性主要取决于组织的安全目标以及安全性所受到的威胁程度 1.1.1 机密性 机密性&#xff1a;限制未授权主…

【C/C++笔试练习】——printf在使用%的注意事项、for循环语句的三个条件、运算符优先级、删除公共字符

文章目录 C/C笔试练习1.%符号在printf用作格式说明符的注意事项&#xff08;1&#xff09;输出%5.3s&#xff08;2&#xff09;判断%中小数点含义 2.for循环语句的三个条件&#xff08;3&#xff09;判断循环次数&#xff08;4&#xff09;判断循环次数 3.运算符优先级&#xf…

计算机专业毕业设计项目推荐08-英语在线点读平台(SpringBoot+Vue+MongoDB)

英语在线点读平台&#xff08;SpringBootVueMongoDB&#xff09; **介绍****系统总体开发情况-功能模块****各部分模块实现** 介绍 本系列(后期可能博主会统一为专栏)博文献给即将毕业的计算机专业同学们,因为博主自身本科和硕士也是科班出生,所以也比较了解计算机专业的毕业设…

【Linux】【网络】传输层协议:UDP

文章目录 UDP 协议1. 面向数据报2. UDP 协议端格式3. UDP 的封装和解包4. UDP 的缓冲区 UDP 协议 UDP传输的过程类似于寄信。 无连接&#xff1a;知道对端的IP和端口号就直接进行传输&#xff0c;不需要建立连接。不可靠&#xff1a;没有确认机制&#xff0c;没有重传机制&am…