(源码不白看)LiveData 源码

源码不白看,面试如何回答

简单的说下 LiveData 原理?

本质上是一个观察者模式,Activity 或 Fragment 中实现观察者,LiveData 是被观察者,LiveData 中存储的数据变更的时候触发事件。

说下 LiveData 的优缺点?

优点:

  1. 响应式编程

由于观察者模式的特性,实现了响应式编程,LiveData 数据变化后自动触发 UI 更新,

  1. 解耦, 对 MVP 模式的补充

没有对比就没有伤害:传统的 MVP 模式在使用的时候,Presenter 中需要传入一个 接口 作为与 View 交互的桥梁,而 LiveData 刚好可以替代了这个 接口。这样 Presenter 中就不需要持有 View(通常是View实现接口传到Presenter中直接使用) 对象,解耦更加彻底

应该还不算是 MVVM, 个人理解使用了 DataBinding 才算 MVVM

  1. 实现了生命周期的监听, 避免内存泄露

缺点:

暂时没想到

LiveData 如何实现生命周期的监听?

这个有点复杂了,很难几句话说清楚。

白话版本:Activity, Fragment 中有一个成员变量,这个对象在 Activity 和 Fragment 的生命周期函数中会执行一个类似 lifecycleChange(event) 的函数并把当前生命周期事件作为参数传入。然后把生命周期 Event 传递给 LiveData。 最后 LiveData 根据生命周期事件判断是否要取消观察者模式的订阅。

专业版本:Activity, Fragment 中有一个成员变量 mLifecycleRegistry,这个对象在 Activity 和 Fragment 的生命周期函数中会执行 mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.XXXX); ,然后把生命周期 Event 传递给 LifecycleObserver。 最后 LifecycleObserver 根据生命周期事件判断是否要取消观察者模式的订阅。

Activity 或者 Fragment 哪些生命周期状态下可以接收事件消息?

onStart, onResume, onPause

不能接收数据的生命周期时(onStop),LiveData 中数据变化会不会生效?

可以生效,在 Activity 回到 onResume 的时候会显示 LiveData 中最新的数据。

知道setValue 和 postValue 的区别吗?

setValue 必须在主线程中执行, postValue 可以在子线程中执行。

如何实现线程切换的?

在内部创建了 MainHandler ,构建一个 RunnableMainHandler 执行,实现线程切换。

LiveData 源码解析

LiveData是一个数据持有者,其本身实现了观察者模式,支持数据监控(被观察),并且可以感知组件的生命周期。

使用

LiveData 是一个抽象类,通常在使用 LiveData 的时候我们是使用其子类 MutableLiveData

XXViewModel.class

// 创建 LiveData
private MutableLiveData<Object> mDataMutableLiveData = new MutableLiveData<>();

// LiveData 改变数据, 触发观察者
mDataMutableLiveData.postValue(object);
// setValue 在主线程中执行
// postValue 可以在子线程中执行

XXActivity:

//获取 ViewModel 对象
mViewModel = ViewModelProviders.of(this).get(XXViewModel.class);

//设置观察者
mViewModel.getDataMutableLiveData().observe(this, this::dataChange);

// LiveData 中数据改变的时候处罚
private void dataChange(Object s) {
    // data change
}

基本概念

LiveData 使用了观察者模式。

  1. 被观察者:LiveData
  2. 观察者,需要实现:LifecycleOwner 接口,Activity, Fragment 都实现了 LifecycleOwner 接口,所以在使用的时候我们通常使用 Activity, Fragment 作为观察者。

观察者唯一的作用是提供:Lifecycle 对象。Lifecycle 是抽象类,实际返回的是 LifecycleRegistry 对象。

LifecycleOwner.class:

public interface LifecycleOwner {
    @NonNull
    Lifecycle getLifecycle();
}

Activity 和 Fragment 中都有成员变量 mLifecycleRegistry,并在 getLifecycle 函数中返回该对象。

private LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);

@Override
public Lifecycle getLifecycle() {
    return mLifecycleRegistry;
}

被观察者添加观察者过程

调用 LiveData#observer 函数

public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer)

android.arch.lifecycle.Observer 是一个接口,里面只有一个函数 onChanged 作为被观察者数据改变后触发的回调函数。

添加观察者过程实际上是把 Observer 传递给 LiveData 对象 和 LifecycleRegistry 对象。

LiveData 中存储 observer:

private SafeIterableMap<Observer<T>, ObserverWrapper> mObservers = new SafeIterableMap<>();

Map: observer: new LifecycleBoundObserver(owner, observer)

LifecycleRegistry 中存储 observer:

private FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap = new FastSafeIterableMap<>();

Map: LifecycleBoundObserver(owner, observer): ObserverWithState(observer, initialState)

LifecycleBoundObserver 对象作为生命周期状态变化后调用函数存在

class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver

生命周期变化后触发:
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event)

到此关键对象:

  1. LiveData: 作为数据入口,维护观察者和被观察者的关系
  2. Observer:数据改变后最终触发的函数,回调接口,调用端实现
  3. LifecycleOwner: Activity, Fragment 提供 Lifecycle
  4. Lifecycle, LifecycleRegistry
  5. LifecycleObserver,GenericLifecycleObserver, LifecycleBoundObserver: 封装了 Observer, LifecycleOwner 对象

Activity 和 Fragment 的生命周期是如何和 LiveData 产生关联的?

LiveData 和 生命周期的关系基本操作:

生命周期正常的时候, addObserver 注册观察者;生命周期结束的时候 removeObserver 取消观察者

上面添加订阅和取消订阅都是内部自动执行的,不需要用户去手动触发。

上面提到 Activity,Fragment 都实现了 LifecycleOwner 接口,成员变量中有 mLifecycleRegistry 对象。

在 Activty, Fragment 生命周期函数中调用下面函数将生命周期事件传递出来:

mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.XXXX);

mLifecycleRegistry 触发生命周期改变函数后,调用下面函数(中间省略了部分步骤)

mLifecycleObserver.onStateChanged(owner, event);

LifecycleBoundObserver 就是这里的 mLifecycleObserver
//根据事件判断是否要解除订阅

setValue 与 postValue

setValue 必须在主线程中执行,postValue 可以在子线程中执行,

如何实现的线程切换?

ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);

ArchTaskExecutor 使用了代理模式, 实际函数执行类是 DefaultTaskExecutor

TaskExecutor 接口
    |- ArchTaskExecutor 实现
    |- DefaultTaskExecutor 实现

Runnable 最终执行位置:

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

线程切换通过 Handler 实现

MainHandler 创建方式:

mMainHandler = new Handler(Looper.getMainLooper());

判断是否是 MainThread:

Looper.getMainLooper().getThread() == Thread.currentThread();
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容