LiveData

news2024/9/23 5:33:17

LiveData是一个抽象类,那么我们从简单的MutableLiiveData开始剖析,先看源码

源码太简洁了,就是继承LiveData,然后重写了父类的方法,并且没有多余的操作,都是直接使用父类方法里的逻辑,那我们就根据这几个方法,来一点一点看liveData

构造函数,也就是传一个泛型T的对象

 就是做一个初始化赋值,有一个mVersion = START_VERSION+1,也很好理解了

来到postValue

   protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }

synchronized对这个代码块上锁,代码块里就是赋值,防止多个线程同时赋值,所以要上锁,第一次的时候mPendingData == NO_SET肯定是true,因为初始化的时候

volatile Object mPendingData = NOT_SET;

然后给mPendingData赋新值,然后post一个任务,这个任务的代码如下

 private final Runnable mPostValueRunnable = new Runnable() {
        @SuppressWarnings("unchecked")
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            setValue((T) newValue);
        }
    };

同样要上锁,防止多线程同时修改值,将mPendingData赋值给newValue,然后又mPendingData = NOT_SET,这里其实有个线程切换,后面剖析,这里及继续追踪到setValue

  @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

有个注解@MainThread,也就是说这个方法一定要在主线程中调用,方法就是将值赋值给mData,这个mData就是构造方法里的mData,它一直在主线程更新,也就是说就算有多线程更新,那么也是一次一次的切换到主线程再更新mData的值

dispatchingValue()的核心代码

        do {
            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);

其实就是观察者,然后通知他们,通知的方法considerNotify

 private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {  //判断观察者是否处于活跃状态
            return;
        }

        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {    //记得versionCode不,这是一个判断是否匹配
            return;
        }
        observer.mLastVersion = mVersion;  //versionCode不同,就赋值 
        observer.mObserver.onChanged((T) mData);    //通知观察者更新
    }

构建liveData的观察者:

//构建liveData的观察者,这里为什么要传一个LifecycleOwner呢,其实就是要知道LifecycleOwner 的生 //命周期,因为liveDta是在activty/fragment在活跃状态的时候才会更新值,也就是说其实liveData也观察了activity/fragment的生命周期
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
        @NonNull
        final LifecycleOwner mOwner;
        //构造函数
        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
            super(observer);
            mOwner = owner;
        }

        @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);    //判断被观察者的最新状态
        }

        //观察了lifecycleOwner的生命周期状态,所以说虽然liveData是被观察者,但是它作为被观察者通样也是一个观察者
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            //页面当前状态
            Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
            if (currentState == DESTROYED) {    //页面都没了
                removeObserver(mObserver);
                return;
            }
            Lifecycle.State prevState = null;
            //状态改变
            while (prevState != currentState) {
                prevState = currentState;
                activeStateChanged(shouldBeActive());
                currentState = mOwner.getLifecycle().getCurrentState();
            }
        }

        @Override
        boolean isAttachedTo(LifecycleOwner owner) {
            return mOwner == owner;
        }

        @Override
        void detachObserver() {        //不用观察了
            mOwner.getLifecycle().removeObserver(this);
        }
    }

其实liveDta是作为一个被观察者,当它的mData发生有效改变的时候,通知他的观察者集合们,同时liveData也是一个观察者啊,它时刻观察者当前activity/fragment的生命周期变化

------------------------------------------------------------

回到postValue,我们都知道在主线程更新liveData可以用setValue,但是在非主线程要更改liveData的值,需要用postValue,我们在上面看到了,就算用postValue,最终也是切到主线程调用setValue,那么我们就来追踪一些这个切换的过程

 因为在子线程中调用,所以我们先锁住我们的判断,防止值被改变,导致判断不准确,当值是改变了,那么核心就来到了

 ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);

我们在子线程,这里有个postToMainThread,我们都知道线程的切换怎么都离不开handler,继续追踪,getInstance,会不会是一个单例呢,没错就是一个单例,切线程的方法postToMainThread

追踪发现一个DefaultTaskExecutor

    @Override
    public void postToMainThread(Runnable runnable) {
        if (mMainHandler == null) {
            synchronized (mLock) {
                if (mMainHandler == null) {
                    mMainHandler = createAsync(Looper.getMainLooper());
                }
            }
        }
        //noinspection ConstantConditions
        mMainHandler.post(runnable);
    }

就是创建一个Handler,只创建一次哈,创建Handler用主线程的Looper,这样runnable就post到主线程的Looper里面的MessageQueue中,主线程Looper循环从MessageQueue中取出message,并交给message.target也就是发送message的handler处理

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

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

相关文章

安全防护的原则

电力行业 工控安全解决思路保障框架从电力行业对工控安全需求看&#xff0c;电力企业在主要是以合规性建设为主&#xff0c;在 2004 年原电监会 5 号令颁布开始&#xff0c;大部 分的电厂控制系统安全 建设已经按照 5 号令的要求进行了整改&#xff0c;形成“安全分区、网络专…

数电笔记总结(三)(逻辑门电路)

目录逻辑门基础逻辑门电路分立元件基本逻辑门电路TTL集成门电路&#xff08;与非门&#xff09;两种特殊门&#xff08;重点&#xff09;1.集电极开路门&#xff08;OC门&#xff09;2.三态门电路逻辑门基础 逻辑门电路 门电路&#xff1a;具有控制信号通过或不通过能力的电路…

某某桥的检测和加固设计

目录 某某大桥桥梁检测及加固设计报告 1 0 总论 2 0.1 检测目的 2 0.2 桥梁结构混凝土强度检测[1] 2 0.3 结构综合评定指标 4 0.4桥梁承载能力[3] 4 0.5 桥梁结构荷载试验 6 0.6 主要结果与结论 8 1某某大桥简介 11 1.1某某大桥简介 11 1.2 检测仪器与设备 15 2 外观检查与检测…

【跟学C++】C++STL标准模板库——算法整理(上)(Study18)

文章目录1、STL简介2、STL算法分类及常用函数2.1、非变序算法2.1.1 计数算法(2个)2.1.2 搜索算法(7个)2.1.3 比较算法(2个)3、总结 【说明】 大家好&#xff0c;本专栏主要是跟学C内容&#xff0c;自己学习了这位博主【 AI菌】的【C21天养成计划】&#xff0c;讲的十分清晰&am…

每个程序员都要知道的一个网站

在日常开发过程中&#xff0c;你是不是经常回到搜索引擎&#xff0c;搜索某个功能的实现方式&#xff0c;比如&#xff1a;Javascript 数组排序、正则表达式等等。 今天给大家推荐的这个网站&#xff0c;就可以满足大家的需求&#xff0c;它叫&#xff1a;30secondsofcode&…

抽象类与接口

目录 1. 抽象类 1.1 抽象类概念 1. 2&#x1f414;抽象类特性 1.3 抽象类的作用 2. 接口 2.1 接口是什么 2.2 语法规则 2.3 方法的使用 2.4 接口特性 2.5 实现接口 VS 继承类 2.6 抽象类 VS 接口&#xff08;总结&#xff09; 2.6 接口间的继承 &#x1f413; 随着…

漫画脸头像怎么制作?这几种方法可以帮到你

你们会经常更换头像吗&#xff1f;我身边就有一些朋友会这样做&#xff0c;看到喜欢的头像就换&#xff0c;而且他基本上都是找那些漫画脸来当头像。那如果我们把自己的人像制作成漫画脸&#xff0c;就不容易跟别人撞头像了&#xff0c;还显得有个性。 估计有很多小伙伴不知道漫…

NXP BootLoader源码分析并改写SD卡启动

1 官方资料 NXP官方提供了MCUBoot SDK&#xff1a;NXP_Kinetis_Bootloader_2.0.0 package&#xff0c;里面包含了各种型号芯片的的BootLoader。 BootLoader参考手册&#xff1a;doc/Kinetis Bootloader v2.0.0 Reference Manual.pdf上位机程序参考手册&#xff1a;Kinetis Fl…

疯狂小杨哥被王海打假

我是卢松松&#xff0c;点点上面的头像&#xff0c;欢迎关注我哦&#xff01; 知名打假人王海 发布视频&#xff0c;说疯狂小杨哥三只羊直播间售卖的金正破壁机和绞肉机虚标功率。破壁机标注功率为300W&#xff0c;实际为105W&#xff0c;绞肉机标注功率300W&#xff0c;实际功…

[附源码]java毕业设计咖啡销售管理系统-

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

总线仲裁的方式

总线仲裁的基本概念 同一时刻只能有一个设备控制总线传输操作&#xff0c;可以有一个或多个设备从总线接收数据。 将总线上所连接的各类设备按其对总线有无控制功能分为&#xff1a; 主设备&#xff1a;获得总线控制权的设备。 从设备&#xff1a;被主设备访问的设备&#xff0…

C++11标准模板(STL)- 算法(std::stable_partition)

定义于头文件 <algorithm> 算法库提供大量用途的函数&#xff08;例如查找、排序、计数、操作&#xff09;&#xff0c;它们在元素范围上操作。注意范围定义为 [first, last) &#xff0c;其中 last 指代要查询或修改的最后元素的后一个元素。 将元素分为两组&#xff0…

内网的基本构造

内网的基本构造 内网也就是常说的局域网(Local Area Network,简称LAN)&#xff0c;是由两个或两个以上相连的计算机组成&#xff0c;局域网是包含在较小区域内的网络&#xff0c;覆盖范围一般是方圆几千米之内&#xff0c;通常位于建筑物内。家庭WiFi网络和小型企业网络是常见…

一次GC暂停时间过长的排查与优化

告警 GC日志分析 日志 2022-11-17T14:28:40.3150800: 1956232.826: [GC (Allocation Failure) 2022-11-17T14:28:40.3150800: 1956232.826: [ParNew: 1576103K->2817K(1769472K), 0.0241066 secs] 4197176K->2624616K(5046272K), 0.0243910 secs] [Times: user0.04 sys…

nginx配置详解

nginx 是一个高性能的HTTP 和反向代理服务器,特点是占有内存少&#xff0c;并发能力强 用途&#xff1a; 可以作为静态页面的 web 服务器正向代理&#xff08;通过nginx代理 访问外部资源&#xff0c;比如fanqiang&#xff09;反向代理 &#xff08;隐藏真实服务器地址&…

创建vite项目

前提&#xff1a;Vite需要Node.js版本> 12.0.0 1. 创建文件夹&#xff0c;文件夹下打开cmd,输入 yarn create vite C:\Users\admin\Desktop\new>yarn create vite 2. 进行选择 3. vite.config.js 配置 &#xff08;注意按目录创建global.scss&#xff09; import …

关于射频测试电缆 这些知识你知道吗?

射频电缆组件的正确选择除了频率范围&#xff0c;驻波比&#xff0c;插入损耗等因素外&#xff0c;还应考虑电缆的机械特性&#xff0c;使用环境和应用要求&#xff0c;另外&#xff0c;成本也是一个永远不变的因素。以下带大家了解射频电缆相关知识。 射频电缆组件的基本选择原…

【附源码】Python计算机毕业设计网上宠物商店系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

Android 天气APP(三十六)运行到本地AS、更新项目版本依赖、去掉ButterKnife

运行到本地AS、更新项目版本依赖、去掉ButterKnife前言正文一、新版Android Studio编译运行① 升级项目gradle版本② 切换JDK版本③ BuildConfig报错二、百度的SDK使用① 开发版SHA1的作用是什么&#xff1f;② 什么时候需要更换开发版SHA1&#xff1f;③ 怎么获取开发版SHA1&a…

STM8S系列基于STVD开发,ADC不同精度采样示例

STM8S系列基于STVD开发&#xff0c;ADC不同精度采样示例&#x1f4cc;相关篇《STM8S系列基于STVD开发&#xff0c;自定义printf函数TIM5精确延时函数模块化工程示例》 ✨本工程以上面一篇的工程为模板&#xff0c;在此基础上实现ADC电压采样。 &#x1f3ac;&#x1f4fd;&…