LiveData简单解析

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Android LiveData

啥是LiveData?

public abstract class LiveData {
    /***/
}复制代码

这个类就是LiveData 本文完!!!

hhh皮一下很开心

简单的介绍一下:

LiveData is a data holder class that can be observed within a given lifecycle.
官方类上面的介绍 简单的说就是可以 
在生命周期内感知到数据变化的一个东东 通过Lifecycle感知当前页面的生命周期 来决定是否要发送数据 
复制代码

如果你还不知道LiveData如何使用 那么建议看一下官方文档  


大召唤法:developer.android.com/topic/libra…

看完上面两个东西 我觉得应该会有两个疑问


1:怎么发送数据?

2:怎么感知生命周期?

ok 我们来一一解答:


question one:LiveData 是怎么做到发送数据的?

ok 用过的小伙伴都知道 使用setValue 和 postValue方法 那么 这两个方法做了啥?

一起来看看


SetValue

/**
 * Sets the value. If there are active observers, the value will be dispatched to them.
 * <p>
 * This method must be called from the main thread. If you need set a value from a background
 * thread, you can use {@link #postValue(Object)}
 *
 * @param value The new value
 */
@MainThread //注解1
protected void setValue(T value) {
    assertMainThread("setValue");//注解2
    mVersion++;
    mData = value;
    dispatchingValue(null);//注解3
}复制代码


注解1:MainThread  该注意代表着被标注的方法 和 类 只能在主线程中进行 如果在类上 整个类的方法都只能在主线程

注解2:assertMainThread  进行线程检查

注解1+注解2 = 我们知道了setValue 只能在主线程中运行  ///Nice 脑壳又进了一点知识复制代码


注解3:从名字看 是给我们观察者派发更新事件的 等下说


PostValue

既然setValue 只能在主线程发送 那么Android中的惯例 就有一个可以在异步线程分派事件的方法

so 决定就是你 皮卡丘(postValue)


/**
 * Posts a task to a main thread to set the given value. So if you have a following code
 * executed in the main thread:
 * <pre class="prettyprint">
 * liveData.postValue("a");
 * liveData.setValue("b");
 * </pre>
 * The value "b" would be set at first and later the main thread would override it with
 * the value "a".
 * <p>
 * If you called this method multiple times before a main thread executed a posted task, only
 * the last value would be dispatched.//如果你多次调用这个方法 那么只使用最后一个值
 *
 * @param value The new value
 */
protected void postValue(T value) {
    boolean postTask;
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        mPendingData = value;
    }
    if (!postTask) {
        return;
    }
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);///注释1   
}
注释1:ArchTaskExecutor调用获取实例方法  然后将任务发送至主线程中/**
 * Returns an instance of the task executor.
 *
 * @return The singleton ArchTaskExecutor.
 */
@NonNull
public static ArchTaskExecutor getInstance() {///一个单利实例获取写法
    if (sInstance != null) {
        return sInstance;
    }
    synchronized (ArchTaskExecutor.class) {
        if (sInstance == null) {
            sInstance = new ArchTaskExecutor();
        }
    }
    return sInstance;
}
///私有构造
private ArchTaskExecutor() {
    mDefaultTaskExecutor = new DefaultTaskExecutor();
    mDelegate = mDefaultTaskExecutor;
}
@Override
public void postToMainThread(Runnable runnable) {
    mDelegate.postToMainThread(runnable);注解1
}复制代码



注解1:这个mDelegate 其实是上面私有构造器的DefaultTaskExecutor()的代理;所以它的postToMainThread方法的具体实现应该如下:

@Override
public void postToMainThread(Runnable runnable) {
    if (mMainHandler == null) {
        synchronized (mLock) { 
            if (mMainHandler == null) {
                mMainHandler = createAsync(Looper.getMainLooper());
            }
        }
    }
    //noinspection ConstantConditions
    mMainHandler.post(runnable);///看到MAinHandler 原来是这样跑到主线程去得
}复制代码


然后 就是问题来了 上面一系列的操作只是把任务切换到主线程运行  那任务呢?任务是啥?

ok 这个时候 我们在看LiveData.postValue 方法中 提交任务的那一块代码


ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);   
哈哈哈找到了 mPostValueRunnable 是你  那这个mPostValueRunnable是什么东西  跟着去看看复制代码
private final Runnable mPostValueRunnable = new Runnable() {
    @Override
    public void run() {
        Object newValue;
        synchronized (mDataLock) {
            newValue = mPendingData;
            mPendingData = NOT_SET;
        }
        //noinspection unchecked
        setValue((T) newValue);///注释1
    }
};复制代码

注释1:好了 原来postValue只是切换线程后 最后还是调用setValue 方法


既然如此让我们再看看 刚刚的setValue中 还未说明的注释3吧

go dispatchingValue(null);//注解3
 @SuppressWarnings("WeakerAccess") /* synthetic access */
void dispatchingValue(@Nullable ObserverWrapper initiator) {
    if (mDispatchingValue) {///注解1:首先先判断是否是正在发送中
        mDispatchInvalidated = true;///是的话 return
        return;
    }
    mDispatchingValue = true;///标记为发送中
    ///一个do whild循环 :dowhile  至少执行一次
    do {
        mDispatchInvalidated = false;
        if (initiator != null) {///判断该initiator  是否为空 setValue传进来的都是null
            considerNotify(initiator);///只更改当前ObserverWrapper 
            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 方法 gogogo 感觉要探宝成功了  


private void considerNotify(ObserverWrapper observer) {
    if (!observer.mActive) {///如果不是活越状态 就不继续发送事件   注解1
        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);
        //传入false  内部会进行判断是否需要再次判断是否执行onActive方法和onInactive方法回调。如果判断条件都满足会调用Observer的onChanged方法
        return;
    }
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;
    //noinspection unchecked
    observer.mObserver.onChanged((T) mData);
    ///哦豁 实现了数据通知
}复制代码



Question two:如何实现感知生命周期?

我们通常在Fragment 或者 Activity中注册监听方法会这样写到

//数据监听
        viewModel.getLiveData().observe(getViewLifecycleOwner(), data-> {
            /***/
        }); 
复制代码

来看看observe做了啥


@MainThread ///主线程
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
    assertMainThread("observe");///标准检查线程
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {///如果是监听的生命周期是销毁状态
        // ignore ///忽略
        return;
    }
    ///创建一个与生命周期绑定的观察者
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);///这个方法做啥了  让我们看看注解1
    if (existing != null && !existing.isAttachedTo(owner)) {///如果existing   就是我们putIfAbsent 返回值 如果不为空 就说明已经绑定过了
        throw new IllegalArgumentException("Cannot add the same observer"
                + " with different lifecycles");
    }
    if (existing != null) {
        return;
    }
    owner.getLifecycle().addObserver(wrapper);///这个时候 就会真的添加进入观察
    Livedata就能够感知生命周期了
    }复制代码

注解1:putIfAbsent

* If the specified key is not already associated
 * with a value, associates it with the given value.
 *
 * @param key key with which the specified value is to be associated
 * @param v   value to be associated with the specified key
 * @return the previous value associated with the specified key,
 * or {@code null} if there was no mapping for the key
 */
public V putIfAbsent(@NonNull K key, @NonNull V v) {
    Entry<K, V> entry = get(key);///具体实现看下面get方法
    if (entry != null) {///如果当前节点不为空 就返回value
        return entry.mValue;
    }
    put(key, v);///否则存储 返回null
    return null;  
}
////get方法
protected Entry<K, V> get(K k) {
    Entry<K, V> currentNode = mStart;///Entry 是一个双向链表
    while (currentNode != null) {///一个whild 循环
        if (currentNode.mKey.equals(k)) {
            ///判断当前链表的k 是否和当前k相等  相等则跳出循环
            break;
        }
        currentNode = currentNode.mNext;///否则等于下个next 
    }
    return currentNode;///最后 如果当前链表中有k则返回当前节点  否则返回的是null 
}
复制代码



到此 两个问题 都解答完了啦

总结:

问题1:postValue  会把LiveData中已经定义好的 mPostValueRunnable  通过一个单利ArchTaskExecutor中postToMainThread方法 将任务提交给 DefaultTaskExecutor 发送至主线程执行runnable方法  而runnable中 会调用setValue  setValue会调用分派数据方法(dispatchingValue) 该方法中进行一系列检测  最终considerNotify啊 然后再检查是否满足发送条件 满足则发送

问题2:调用observe  检查生命周期状态是否是销毁的  不是销毁的话 创建一个与生命周期进行绑定的 观察者 LifecycleBoundObserver 然后再进行一系列检查是否满足条件 满足就执行

owner.getLifecycle().addObserver(wrapper);  添加观察


作者:FeanCheng

链接:https://juejin.cn/post/6844904088241455112

来源:掘金

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

目录
相关文章
Livedata源码详细解析-面试这么讲就ok
Livedata源码详细解析-面试这么讲就ok
298 0
Livedata源码详细解析-面试这么讲就ok
|
2月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
86 2
|
3月前
|
缓存 Java 程序员
Map - LinkedHashSet&Map源码解析
Map - LinkedHashSet&Map源码解析
87 0
|
3月前
|
算法 Java 容器
Map - HashSet & HashMap 源码解析
Map - HashSet & HashMap 源码解析
68 0
|
3月前
|
存储 Java C++
Collection-PriorityQueue源码解析
Collection-PriorityQueue源码解析
73 0
|
3月前
|
安全 Java 程序员
Collection-Stack&Queue源码解析
Collection-Stack&Queue源码解析
96 0
|
7天前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
|
7天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
7天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是"将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。创建型模式分为5种:单例模式、工厂方法模式抽象工厂式、原型模式、建造者模式。
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
2月前
|
缓存 监控 Java
Java线程池提交任务流程底层源码与源码解析
【11月更文挑战第30天】嘿,各位技术爱好者们,今天咱们来聊聊Java线程池提交任务的底层源码与源码解析。作为一个资深的Java开发者,我相信你一定对线程池并不陌生。线程池作为并发编程中的一大利器,其重要性不言而喻。今天,我将以对话的方式,带你一步步深入线程池的奥秘,从概述到功能点,再到背景和业务点,最后到底层原理和示例,让你对线程池有一个全新的认识。
56 12

推荐镜像

更多