Android Jetpack库剖析之LiveData组件篇

目录
  • LiveData简介
  • LiveData用法
  • 数据订阅过程
  • PostValue过程
  • SetValue过程
  • 生命周期变化

LiveData简介

在日常安卓开发中,一些耗时的操比如列网络请求,数据库读写都不能在主线程执行,必须开一条子线程去执行这些耗时操作,但我们往往需要在这些耗时操作执行完毕后更新UI,但安卓不能在子线程进行UI的更新,这时我们只能通过创建一个Handler来切回到主线程进行UI的更新,直到LiveData出现,LiveData是一个可被观察的数据容器,它将数据包装起来,使数据成为被观察者。当数据发生改变时,观察者能够及时得到通知。

LiveData用法

LiveData是一个数据容器,订阅视图的生命周期,在子线程通过postValue()切换到主线程来传递数据给观察者,当视图是活动的状态下观察者即可接受到数据,LiveData是一个典型的观察者模式。

class MainActivity : AppCompatActivity() {
    private val mLiveData = MutableLiveData<String>()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = ActivityMainBinding.inflate(LayoutInflater.from(baseContext))
        setContentView(binding.root)
        mLiveData.observe(this, {
            binding.tvContent.text = it
        })
        Thread(BackgroundThread(mLiveData)).start()
    }
    private class BackgroundThread(liveData: MutableLiveData<String>) : Runnable {
        private val mLive = WeakReference(liveData)
        override fun run() {
            mLive.apply {
                get()?.apply {
                    postValue("hello LiveData")
                }
            }
        }
    }
}

数据订阅过程

@MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        //1,判断是否在主线程
        assertMainThread("observe");
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        //2,通过owner,observer来构建一个LifecycleBoundObserver
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        //3,把observer存放到mObservers中
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        //4,如果existing不为空代表观察者已经存在并且已经绑定了生命周期,抛一个Exception来提示
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        //5,调用Lifecycle的addObserver()方法来订阅生命周期
        owner.getLifecycle().addObserver(wrapper);
    }

1,先判断当前订阅数据这个操作是否是在主线程中执行,否则的话抛一个Exception

2,把owner,observer传入到LifecycleBoundObserver构建出一个LifecycleBoundObserver对象

3,调用mObservers.putIfAbsent()方法把观察者放到观察者集合中,mObservers是SafeIterableMap类型的集合类似Map,但它是通过链表的方式来实现Map接口,SafeIterableMap.putIfAbsent()方法与Map.put()方法不一样,如果根据key获取的value不为null,就将当前的value返回,如果为null,就将当前的键值对存储起来,然后返回一个null

4,existing不为null,代表Observer存在,就抛一个Exception来提示开发者:无法添加具有不同生命周期的同一观察者

5,existing为null,代表observer不存在,添加观察者来观察生命周期拥有者的生命周期,

当我们的视图的生命周期发生改变,LifecycleBoundObserver的onStateChange()方法就会被调用

PostValue过程

protected void postValue(T value) {
        boolean postTask;
        //判断当前是否正在下发数据
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        //如果正在下发数据则继续下发数据
        if (!postTask) {
            return;
        }
        //构建Handler并关联主线程的Looper,回到主线程执行run方法中的逻辑
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }
private final Runnable mPostValueRunnable = new Runnable() {
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            //在主线程中调用setValue来执行数据下发逻辑
            //noinspection unchecked
            setValue((T) newValue);
        }
    };

当调用postValue()方法是通过构建一个Handler并关联主线程的Looper来post一个Runnable来回到主线程执行run方法里面的逻辑,而mPostValueRunnable的run()方法则调用了setValue()方法来实现数据的发送

SetValue过程

@MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }
void dispatchingValue(@Nullable ObserverWrapper initiator) {
        //1,判断当前是正在下发数据
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            //2,如果initiator不为空直接给initiator发送数据更新通知
            if (initiator != null) {
                considerNotify(initiator);
                initiator = null;
            } else {
                /,3,否则遍历所有observer
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    /4,发送数据更新通知
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }
private void considerNotify(ObserverWrapper observer) {
        5,如果当前observer不是活动状态,不下发数据
        if (!observer.mActive) {
            return;
        }
        6,如果当前observer的状态至少不是started状态(可见状态),resumed比started高一个级别(可触摸状态)则不下发数据
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        7,判断数据版本号 如果当前observer的数据是最新的 则不下发数据
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        8,记录最新数据版本号
        observer.mLastVersion = mVersion;

        9,通知数据更新
        observer.mObserver.onChanged((T) mData);
    }
     @Override
        boolean shouldBeActive() {
            判断当前状态是否>=STARTED
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

1,检查当前是否在主线程

2, 每次调用setValue()方法版本号(mVersion)都进行累加

3,把需要新数据赋值给mData

4,调用dispatchingValue来执行数据下发

5,如果initiator不为null则直接给这个观察者下发数据更新通知

6,否则遍历所有的观察者,逐个下发数据更新通知

7,判断当前的observer是否为活动状态,不是活动状态不下发数据,这也就是为什么我们界面不可见时数据不会更新的原因(onStop状态)

8,判断当前的observer是否是resumed状态,不是resumed状态不下发数据,这就是为什么当我们的页面可见但不可触摸时数据不更新的原因(onPause状态)

9,比对数据版本号,如果当前observer的数据是最新数据则不需要下发

10,记录数据版本号并通知observer数据更新,回调observer的onChanged()方法

生命周期变化

@Override
        public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
            1,如果当前的状态为destroyed就移除observer
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            2,更新状态并下发数据
            activeStateChanged(shouldBeActive());
        }
void activeStateChanged(boolean newActive) {
            3,如果新状态和当前状态一致的话不需要更新
            if (newActive == mActive) {
                return;
            }
            4,记录新状态
            mActive = newActive;
            boolean wasInactive = LiveData.this.mActiveCount == 0;
            LiveData.this.mActiveCount += mActive ? 1 : -1;
            if (wasInactive && mActive) {
                onActive();
            }
            if (LiveData.this.mActiveCount == 0 && !mActive) {
                onInactive();
            }
            5,如果是活动状态 下发数据
            if (mActive) {
                dispatchingValue(this);
            }
        }

在订阅数据那一刻(即调用LiveData.observer())就构建了一个LifecycleBoundObserver并且让LifecycleBoundObserver订阅了页面生命周期,所以当页面的生命周期发生改变,LifecycleBoundObserver的onStateChanged()方法都会被调用

1,如果当前页面的状态为destroyed(即销毁状态),则移除观察者

2,更新状态并下发数据

3,判断当前observer的状态跟新状态是否一致,如果时是则不需要更新状态以及数据

4,记录当前observer的状态

5,调用dispatchingValue()并传入当前observer,执行准确下发数据业务

到此这篇关于Android Jetpack库剖析之LiveData组件篇的文章就介绍到这了,更多相关Android LiveData内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解Android JetPack之LiveData的工作原理

    前言 本篇文章主要讲解LiveData工作的原理,如果还不知道LiveData如何用的话,请参考官方文档. LiveData的讲解涉及到了Lifecycle的知识,如果你还不了解LifeCycle,请参考文档LifeCycle介绍. 介绍 LiveData是一个数据持有类,它可以通过添加观察者被其他组件观察其变更.不同于普通的观察者,它最重要的特性就是遵从应用程序的生命周期,如在Activity中如果数据更新了但Activity已经是destroy状态,LivaeData就不会通知Activit

  • Android LiveData使用需要注意的地方

    关于LiveData是什么以及基本使用方式,请参考官方文档:developer.android.com/topic/libra- 简单来说,LiveData是一个可被观察的数据容器类.它将数据包装起来,使得数据成为"被观察者",页面成为"观察者".当ViewModel存放页面所需要的各种数据发生变化时,通过LiveData的方式实现对页面的通知,完成ViewModel与页面组件之间的通信. 那么在使用时发现有以下几个地方需要注意: 1.回调通知 LiveData的观

  • Android mvvm之LiveData原理案例详解

    1. 生命周期感知 1.1 生命周期感知组件 我们知道,Controller(Activity or Fragment) 都是有生命周期的,但是传统的 Controller 实现方式只负责 Controller 本身的生命周期管理,而与业务层的数据之间并没有实现良好解耦的生命周期事件交换.所以业务层都需要自己主动去感知 Controller 生命周期的变化,并在 Controller 的生存期处理数据的保活,而在消亡时刻解除与 Controller 之间的关系,这种处理方式随着业务规模的扩大往往

  • Android Jetpack库剖析之Lifecycle组件篇

    目录 提纲 什么是Lifecycle 如何使用Lifecycle 关系梳理 Activity是如何实现Lifecycle的 CompatActivity AppCompatActivity Fragment是如何实现Lifecycle的 Lifecycle是如何下发宿主生命周期给观察者的 提纲 1,什么是Lifecycle? 2,如何使用Lifecycle? 3,LifecycleOwner,Lifecycle,LifecycleObserver之间是什么关系? 3,Activity是如何实现L

  • Android-ViewModel和LiveData使用详解

    ViewModel类的设计目的是以一种关注生命周期的方式存储和管理与UI相关的数据. 例如:Activity在配置发生改变时(屏幕旋转),Activity就会重新创建,onCreate()方法也会重新调用.我们可以在onSaveInstanceState()方法中保存数据,并从onCreate()方法中通过Bundle恢复数据,但这种方法只适用于可以对其进行序列化的少量数据,而不适用于潜在的大量数据.使用ViewModel的话ViewModel会自动保留之前的数据并给新的Activity或Fra

  • Android 基于MediatorLiveData实现红点的统一管理

    目录 背景 需求分析 思路分析 树形模型 具体代码实现 MediatorLiveData RedPointManager 验证刷新逻辑 总结 背景 小红点在各个App内随处可见,并且随着需求的不断迭代,需要展示小红点的需求越来越多. 不同需求之间,红点显示可能有冲突. 不同页面之间,红点显示会有关联. 同一个红点,可能显示成数字样式,红点样式,文案样式. 这个时候,如果没有对红点的展示逻辑做一个统一的抽象和管理的话,就会感觉很复杂,后续也不太好维护. 本文会基于MediatorLiveData,

  • Android Jetpack库剖析之LiveData组件篇

    目录 LiveData简介 LiveData用法 数据订阅过程 PostValue过程 SetValue过程 生命周期变化 LiveData简介 在日常安卓开发中,一些耗时的操比如列网络请求,数据库读写都不能在主线程执行,必须开一条子线程去执行这些耗时操作,但我们往往需要在这些耗时操作执行完毕后更新UI,但安卓不能在子线程进行UI的更新,这时我们只能通过创建一个Handler来切回到主线程进行UI的更新,直到LiveData出现,LiveData是一个可被观察的数据容器,它将数据包装起来,使数据

  • Android Jetpack库剖析之ViewModel组件篇

    前言 今天让我们一起去探究一下ViewModel的实现原理,描述的不对或不足还请海涵,仅作为参考 ViewModel简介 ViewModel是一个可感知Activity或Fragment生命周期的一个架构组件,当视图销毁,数据也会被清除,所以它的本质就是用来存储与视图相关的数据,让视图显示控制与数据分离,即使界面配置发生改变数据也不会被销毁,通常配合LiveData使用 ViewModel用法 class MainActivity : AppCompatActivity() { override

  • Android Jetpack库重要组件WorkManager的使用

    目录 前言 后台处理指南 后台处理面临的挑战 如何选择合适的后台解决方案 WorkManager概述 WorkManager使用 1 声明依赖项 2 自定义一个继承自Worker的类 3 选择worker执行的条件 4 下面贴出自定义worker类的全部源码 5 执行任务的方式 6 取消任务的执行 前言 WorkManager是Jetpack很重要的一个组件: 本篇我们就先来讲讲它是如何使用的,在讲解之前我们先了解关于后台处理的一些痛点 后台处理指南 我们知道每个 Android 应用都有一个主

  • Android开发中用Kotlin编写LiveData组件教程

    目录 1.简单使用 2.map和switchMap LiveData是Jetpack提供的一种响应式编程组件,它可以包含任何类型的数据,并在数据发生变化的时候通知给观察者.也就是说,我们可以将数据使用LiveData来包装,然后在Activity中去观察它,就可以主动将数据变化通知给Activity了. 1.简单使用 class MainViewModel(countReserved:Int) : ViewModel() { /*当外部调用counter变量时,实际上获得的就是_counter的

  • Android Jetpack组件支持库DataBinding与ViewModel与LiveData及Room详解

    目录 一.官方推荐的Jetpack架构 二.添加依赖 三.创建Repository 四.创建ViewModel 五.activity中使用 Android Jetpack之ViewModel.LiveData Android Jetpack之LifeCycle 一.官方推荐的Jetpack架构 ViewModel是介于View(视图)和Model(数据模型)之间的中间层,能够使视图和数据分离,又能提供视图和数据之间的通信. LiveData是一个能够在ViewModel中数据发生变化时通知页面刷

  • Android Jetpack组件库LiveData源码深入探究

    目录 前言 一.LiveData 二.使用案例 三.LiveData 实现原理 四.LiveData 相关源码 五.LiveData分发问题 Android Jetpack之ViewModel.LiveData Android Jetpack之LifeCycle Android Jetpack之DataBinding+ViewModel+LiveData+Room 前言 Jetpack是一个由多个技术库组成的套件,可帮助开发者遵循最佳做法,减少样板代码并编写可在各种Android版本和设备中一致

  • Android Jetpack组件中LifeCycle作用详细介绍

    目录 Jetpack 1.那么Jetpack是什么呢 2.为何使用Jetpack 3.Jetpack与AndroidX LifeCycle 1.LifeCycle的作用 2.LifeCycle应用 1.设计组件 2.使用组件 3.总结LifeCycle的使用 Jetpack Jetpack,我觉得翻译为“飞行器”更好听,因为Google针对编程历史乱象,整理出一套组件库,帮助开发者创造更完美的应用作品.现在市面上,很多公司招聘面试要求渐渐把Jetpack看作必会技能,Google也在疯狂的安利J

  • Android JetPack组件的支持库Databinding详解

    目录 简介 启用databinding 布局xml variable (变量标签) data (数据标签) @{}表达式 绑定普通数据 绑定可观察数据 对单个变量的绑定-fields 对集合的绑定-collections 绑定对象-objects 绑定LiveData 双向绑定 简介 DataBinding 是 Google 在 Jetpack 中推出的一款数据绑定的支持库,利用该库可以实现在页面组件中直接绑定应用程序的数据源.使其维护起来更加方便,架构更明确简介. DataBinding 唯一

  • Android Jetpack 组件LiveData源码解析

    目录 前言 基本使用 疑问 源码分析 Observer ObserverWrapper LifecycleBoundObserver MutableLiveData postValue setValue 问题答疑 LiveData 特性引出的问题 问题解决 最后 前言 本文来分析下 LiveData 的源码,以及其在实际开发中的一些问题. 基本使用 一般来说 LiveData 都会配合 ViewModel 使用,篇幅原因关于 ViewModel 的内容将在后续博客中分析,目前可以将 ViewMo

随机推荐