Livedata源码详细解析-面试这么讲就ok

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Livedata源码详细解析-面试这么讲就ok

时序图


不太擅长画图,勉强画了一幅

如果您对Livedata的源码有一定了解看了这个图应该就差不多了。

如果对Livedata源码了解不多,那么粗略看一下图,然后直接看后面的逻辑。看完逻辑回过头再细看时序图效果更佳

image.png


Livedata 方法调用简单说明


既然是源码解析,自然入口就是我们的方法调用,这里简单把注册 Livedata 的数据监听和 Livedata.setValue 方法进行简单说明


注册监听代码

mapViewModel.mapLiveData.observe(this,{//这个回调中会收到数据更改的监听
            logEE(it)
            tv_map.text=it
        })
复制代码


数据更改,发送数据

val userLivedata =MutableLiveData<User>()
 fun sendData() {
        userLivedata.value=User("李白",1200)//这句代码发送最新数据
    }
复制代码

下一节就是 Livedata 的工作流程简单分析了


Livedata 代码逻辑


我主要把代码逻辑分为了三部分:

  1. 业务代码 Livedata.observe 注册数据观察
  2. setValue 发送最新数据
  3. 用户视图回到前台自动进行数据分发


第一部分逻辑:

基本的逻辑就是我们注册数据监听的时候,会传入一个 LifeCycle 的数据监听者接口。Livedata 的 observe 方法会将接口封装成一个 LifecycleBoundObserver对象,并且注册 LifeCycle 的生命周期监听。


第二部分逻辑:

当我们调用 Livedata.setValue 方法的时候,会逐个遍历每一个注册的 LifecycleBoundObserver,然后分别调用 Observer 的 onChange 回调方法向我们的业务数据监听返回数据


第三部分逻辑:

因为我们注册了 LifeCycle 的生命周期,当用户视图回到前台的时候会回调 LifecycleBoundObserver 的 onStateChanged 方法。onStateChanged 方法内会进行数据的分发


本节讲了 Livedata 的基本逻辑,下一节主角就是代码了


结合代码讲解逻辑


注册 Livedata 监听

  1. observe 方法体
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        assertMainThread("observe");
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {//如果生命周期已经被销毁,return。这说明了使用Livedata不会发生内存泄露的原因
            // ignore
            return;
        }
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);//这个对象是LifecycleEventObserver的一个实现,是我们注册生命周期组件的观察者
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);//将wrapper加入到map中,得到上一个wrapper,
        if (existing != null && !existing.isAttachedTo(owner)) {//isAttachedTo:上一个wrapper关联的生命周期如果不是当前生命周期,就抛出异常
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {如果上一个wrapper不为空就return(因为会复用上一个wrapper)
            return;
        }
        owner.getLifecycle().addObserver(wrapper);//如果上一个为空则说明是第一次,需要注册生命周期监听
    }
复制代码


Livedata.setValue

  1. 首先看一下 setValue 方法体:
protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;//数据的版本,每次调用setValue都会++
        mData = value;
        dispatchingValue(null);//分发数据
    }
复制代码


  1. 我们发现发法最后调用了 dispatchingValue 方法,那么就再看一下 dispatchingValue 方法体吧
void dispatchingValue(@Nullable ObserverWrapper initiator) {
          if (mDispatchingValue) {// 1、如果正在分发中则返回
              mDispatchInvalidated = true;// 2、目的是如果有新的setValue方法被调用,会在步骤4中跳出for循环,重新再进行一次分发
              return;
          }
          mDispatchingValue = true;、// 3、设置正在分发中状态为true,防止1中重复进入分发消息
          do {
              mDispatchInvalidated = false;// 4、进入循环后设置mDispatchInvalidated为false,如果用户重新setValue需要将mDispatchInvalidated重新设置为true,一边可以在上一轮分发结束后继续走一轮分发
              if (initiator != null) {
                  considerNotify(initiator);// 5、分发消息
                  initiator = null;
              } else {
                  for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                          mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                      considerNotify(iterator.next().getValue());// 6、循环中分发消息
                      if (mDispatchInvalidated) {//6、如果这里为true说明用户又设置了一次value,那么跳出for循环,重新执行外层的dowhile循环
                          break;
                      }
                  }
              }
          } while (mDispatchInvalidated);
          mDispatchingValue = false;//7、消息分发完成,设置正在分发中状态为false
      }
复制代码


3.通过分析,我们发现 dispatchingValue 方法内最终再次分发消息的方法是 considerNotify,方法体:

private void considerNotify(ObserverWrapper observer) {
              if (!observer.mActive) {//1、如果当前lifecycle不是活跃状态就返回不进行消息分发,销毁会在生命周期最近变活跃的时候自动分发
                  return;
              }
              if (!observer.shouldBeActive()) {//2、如果lifecycle状态为started||resumed
                  observer.activeStateChanged(false);//3、激活状态,activeStateChanged方法里面会再次调用dispatchValue分发消息,一般用作livedata从不活跃状态回到活跃状态的时候自动分发消息
                  return;
              }
              if (observer.mLastVersion >= mVersion) {//4、如果true,说明第6步中有更小版本的消息正在调用,所以返回
                  return;
              }
              observer.mLastVersion = mVersion;//5、记住当前正在分发value的版本,用于第四部中的逻辑判断
              observer.mObserver.onChanged((T) mData);//6、调用注册livedata的observer的onChanged通知用户更新数据
          }
复制代码


considerNotify 方法中调用了 mObserver.onChanged 后就会回调我们业务代码中的消息注册监听,整个数据流转的逻辑就完成了


视图重新回到前台

逻辑同 Livedata.setValue

我们知道我们是通过 LifeCycle 生命周期组件来监听生命周期的。

监听生命周期的接口实现就是 LifecycleBoundObserver 类,当生命周期发生改变的时候会回调 LifecycleBoundObserver 类的方法 onStateChanged:

  1. onStateChanged 方法体如下
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();//重置生命周期状态
            }
        }
复制代码


  1. activeStateChanged 方法体
void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;
            }
            mActive = newActive;
            changeActiveCounter(mActive ? 1 : -1);
            if (mActive) {
                dispatchingValue(this);//看到这里你直接去找上一节Livedata.setValue的源码分析就ok了
            }
        }
复制代码


postValue

实际没啥好说的,就是将线程切回到主线程,然后调用 Livedata.setValue 更新数据而已。



相关文章
|
1天前
|
Java 数据库连接 Maven
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
自动装配是现在面试中常考的一道面试题。本文基于最新的 SpringBoot 3.3.3 版本的源码来分析自动装配的原理,并在文未说明了SpringBoot2和SpringBoot3的自动装配源码中区别,以及面试回答的拿分核心话术。
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
|
1天前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
|
1天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
1天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是"将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。创建型模式分为5种:单例模式、工厂方法模式抽象工厂式、原型模式、建造者模式。
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
25天前
|
缓存 监控 Java
Java线程池提交任务流程底层源码与源码解析
【11月更文挑战第30天】嘿,各位技术爱好者们,今天咱们来聊聊Java线程池提交任务的底层源码与源码解析。作为一个资深的Java开发者,我相信你一定对线程池并不陌生。线程池作为并发编程中的一大利器,其重要性不言而喻。今天,我将以对话的方式,带你一步步深入线程池的奥秘,从概述到功能点,再到背景和业务点,最后到底层原理和示例,让你对线程池有一个全新的认识。
53 12
|
21天前
|
PyTorch Shell API
Ascend Extension for PyTorch的源码解析
本文介绍了Ascend对PyTorch代码的适配过程,包括源码下载、编译步骤及常见问题,详细解析了torch-npu编译后的文件结构和三种实现昇腾NPU算子调用的方式:通过torch的register方式、定义算子方式和API重定向映射方式。这对于开发者理解和使用Ascend平台上的PyTorch具有重要指导意义。
|
21天前
|
存储 缓存 Java
Spring面试必问:手写Spring IoC 循环依赖底层源码剖析
在Spring框架中,IoC(Inversion of Control,控制反转)是一个核心概念,它允许容器管理对象的生命周期和依赖关系。然而,在实际应用中,我们可能会遇到对象间的循环依赖问题。本文将深入探讨Spring如何解决IoC中的循环依赖问题,并通过手写源码的方式,让你对其底层原理有一个全新的认识。
41 2
|
21天前
|
Java 程序员
面试官的加分题:super关键字全解析,轻松应对!
小米,29岁程序员,通过一个关于Animal和Dog类的故事,详细解析了Java中super关键字的多种用法,包括调用父类构造方法、访问父类成员变量及调用父类方法,帮助读者更好地理解和应用super,应对面试挑战。
36 3
|
2天前
|
安全 搜索推荐 数据挖掘
陪玩系统源码开发流程解析,成品陪玩系统源码的优点
我们自主开发的多客陪玩系统源码,整合了市面上主流陪玩APP功能,支持二次开发。该系统适用于线上游戏陪玩、语音视频聊天、心理咨询等场景,提供用户注册管理、陪玩者资料库、预约匹配、实时通讯、支付结算、安全隐私保护、客户服务及数据分析等功能,打造综合性社交平台。随着互联网技术发展,陪玩系统正成为游戏爱好者的新宠,改变游戏体验并带来新的商业模式。
|
1月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
76 2

推荐镜像

更多