MVVM系列之二:LiveData

mLiveData.setValue(“onStart”);//活跃状态,会回调onChanged。并且value会覆盖onCreate、onStop中设置的value

}

@Override

protected void onResume() {

super.onResume();

Log.i(TAG, "onResume: ");

mLiveData.setValue(“onResume”);//活跃状态,回调onChanged

}

@Override

protected void onPause() {

super.onPause();

Log.i(TAG, "onPause: ");

mLiveData.setValue(“onPause”);//活跃状态,回调onChanged

}

@Override

protected void onStop() {

super.onStop();

Log.i(TAG, "onStop: ");

mLiveData.setValue(“onStop”);//非活跃状态,不会回调onChanged。后面变为活跃时,value被onStart中的value覆盖

}

@Override

protected void onDestroy() {

super.onDestroy();

Log.i(TAG, "onDestroy: ");

mLiveData.setValue(“onDestroy”);//非活跃状态,且此时Observer已被移除,不会回调onChanged

}

}

注意到 LiveData实例mLiveData的创建是使用MutableLiveData,它是LiveData的实现类,且指定了源数据的类型为String。然后创建了接口Observer的实例,实现其onChanged()方法,用于接收源数据的变化。observer和Activity一起作为参数调用mLiveData的observe()方法,表示observer开始观察mLiveData。然后Activity的所有生命周期方法中都调用了mLiveData的setValue()方法。 结果日志打印如下:

//打开页面,

2020-11-22 20:23:29.865 13360-13360/com.hfy.androidlearning I/Lifecycle_Test: onCreate:

2020-11-22 20:23:29.867 13360-13360/com.hfy.androidlearning I/Lifecycle_Test: onStart:

2020-11-22 20:23:29.868 13360-13360/com.hfy.androidlearning I/Lifecycle_Test: onChanged: onStart

2020-11-22 20:23:29.869 13360-13360/com.hfy.androidlearning I/Lifecycle_Test: onResume:

2020-11-22 20:23:29.869 13360-13360/com.hfy.androidlearning I/Lifecycle_Test: onChanged: onResume

//按Home键

2020-11-22 20:23:34.349 13360-13360/com.hfy.androidlearning I/Lifecycle_Test: onPause:

2020-11-22 20:23:34.349 13360-13360/com.hfy.androidlearning I/Lifecycle_Test: onChanged: onPause

2020-11-22 20:23:34.368 13360-13360/com.hfy.androidlearning I/Lifecycle_Test: onStop:

//再点开

2020-11-22 20:23:39.145 13360-13360/com.hfy.androidlearning I/Lifecycle_Test: onStart:

2020-11-22 20:23:39.146 13360-13360/com.hfy.androidlearning I/Lifecycle_Test: onChanged: onStart

2020-11-22 20:23:39.147 13360-13360/com.hfy.androidlearning I/Lifecycle_Test: onResume:

2020-11-22 20:23:39.147 13360-13360/com.hfy.androidlearning I/Lifecycle_Test: onChanged: onResume

//返回键退出

2020-11-22 20:23:56.753 14432-14432/com.hfy.androidlearning I/Lifecycle_Test: onPause:

2020-11-22 21:23:56.753 14432-14432/com.hfy.androidlearning I/Lifecycle_Test: onChanged: onPause

2020-11-22 20:23:58.320 14432-14432/com.hfy.androidlearning I/Lifecycle_Test: onStop:

2020-11-22 20:23:58.322 14432-14432/com.hfy.androidlearning I/Lifecycle_Test: onDestroy:

  • 首先打开页面,onCreate()中setValue,由于activity是非活跃状态,不会立即回调onChanged。当走到onStart()变为活跃时,onChanged被调用,但value被onStart()中setValue的value覆盖,所以打印的是onChanged: onStart。(为啥不是连续打印两次呢?,是因为ON_START事件是在onStart() return之后,即onStart()走完之后才变为活跃<详见上一篇>,此时observer接收最新的数据。) 接着走到onResume(),也setValue了,同样是活跃状态,所以立刻回调onChanged,打印onChanged: onResume

  • 按Home键时,onPause()中setValue,活跃状态,立刻回调onChanged方法。onStop()执行时已经变为非活跃状态,此时setValue不会立即回调onChanged方法。

  • 再点开时,走到onStart()变为活跃时,onChanged被调用,但value被onStart()中setValue的value覆盖,所以打印的是onChanged: onStart。接着走到onResume(),也setValue了,同样是活跃状态,所以立刻回调onChanged。

  • 返回键退出时,onPause()/onStop()的效果和按Home键一样。onDestroy()中setValue,此时非活跃状态,且此时observer已被移除,不会回调onChanged。

另外,除了使用observe()方法添加观察者,也可以使用observeForever(Observer) 方法来注册未关联 LifecycleOwner的观察者。在这种情况下,观察者会被视为始终处于活跃状态。

2.2 扩展使用


扩展包括两点:

  1. 自定义LiveData,本身回调方法的覆写:onActive()、onInactive()。

  2. 实现LiveData为单例模式,便于在多个Activity、Fragment之间共享数据。

官方的例子如下:

public class StockLiveData extends LiveData {

private static StockLiveData sInstance; //单实例

private StockManager stockManager;

private SimplePriceListener listener = new SimplePriceListener() {

@Override

public void onPriceChanged(BigDecimal price) {

setValue(price);//监听到股价变化 使用setValue(price) 告知所有活跃观察者

}

};

//获取单例

@MainThread

public static StockLiveData get(String symbol) {

if (sInstance == null) {

sInstance = new StockLiveData(symbol);

}

return sInstance;

}

private StockLiveData(String symbol) {

stockManager = new StockManager(symbol);

}

//活跃的观察者(LifecycleOwner)数量从 0 变为 1 时调用

@Override

protected void onActive() {

stockManager.requestPriceUpdates(listener);//开始观察股价更新

}

//活跃的观察者(LifecycleOwner)数量从 1 变为 0 时调用。这不代表没有观察者了,可能是全都不活跃了。可以使用hasObservers()检查是否有观察者。

@Override

protected void onInactive() {

stockManager.removeUpdates(listener);//移除股价更新的观察

}

}

为了观察股票价格变动,继承LiveData自定义了StockLiveData,且为单例模式,只能通过get(String symbol)方法获取实例。 并且重写了onActive()、onInactive(),并加入了 开始观察股价更新、移除股价更新观察 的逻辑。

  • onActive()调用时机为:活跃的观察者(LifecycleOwner)数量从 0 变为 1 时。

  • onInactive()调用时机为:活跃的观察者(LifecycleOwner)数量从 1 变为 0 时。

也就是说,只有当 存在活跃的观察者(LifecycleOwner)时 才会连接到 股价更新服务 监听股价变化。使用如下:

public class MyFragment extends Fragment {

@Override

public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {

super.onViewCreated(view, savedInstanceState);

//获取StockLiveData单实例,添加观察者,更新UI

StockLiveData.get(symbol).observe(getViewLifecycleOwner(), price -> {

// Update the UI.

});

}

}

由于StockLiveData是单实例模式,那么多个LifycycleOwner(Activity、Fragment)间就可以共享数据了。

2.3 高级用法


如果希望在将 LiveData 对象分派给观察者之前对存储在其中的值进行更改,或者需要根据另一个实例的值返回不同的 LiveData 实例,可以使用LiveData中提供的Transformations类。

2.3.1 数据修改 - Transformations.map

//Integer类型的liveData1

MutableLiveData liveData1 = new MutableLiveData<>();

//转换成String类型的liveDataMap

LiveData liveDataMap = Transformations.map(liveData1, new Function<Integer, String>() {

@Override

public String apply(Integer input) {

String s = input + " + Transformations.map";

Log.i(TAG, "apply: " + s);

return s;

}

});

liveDataMap.observe(this, new Observer() {

@Override

public void onChanged(String s) {

Log.i(TAG, "onChanged1: "+s);

}

});

liveData1.setValue(100);

使用很简单:原本的liveData1 没有添加观察者,而是使用Transformations.map()方法 对liveData1的数据进行的修改 生成了新的liveDataMap,liveDataMap添加观察者,最后liveData1设置数据 。

此例子把 Integer类型的liveData1 修改为String类型的liveDataMap。结果如下:

2020-12-06 17:01:56.095 21998-21998/com.hfy.androidlearning I/Lifecycle_Test: apply: 100 + Transformations.map

2020-12-06 17:01:56.095 21998-21998/com.hfy.androidlearning I/Lifecycle_Test: onChanged1: 100 + Transformations.map

2.3.2 数据切换 - Transformations.switchMap

如果想要根据某个值 切换观察不同LiveData数据,则可以使用Transformations.switchMap()方法。

//两个liveData,由liveDataSwitch决定 返回哪个livaData数据

MutableLiveData liveData3 = new MutableLiveData<>();

MutableLiveData liveData4 = new MutableLiveData<>();

//切换条件LiveData,liveDataSwitch的value 是切换条件

MutableLiveData liveDataSwitch = new MutableLiveData<>();

//liveDataSwitchMap由switchMap()方法生成,用于添加观察者

LiveData liveDataSwitchMap = Transformations.switchMap(liveDataSwitch, new Function<Boolean, LiveData>() {

@Override

public LiveData apply(Boolean input) {

//这里是具体切换逻辑:根据liveDataSwitch的value返回哪个liveData

if (input) {

return liveData3;

}

return liveData4;

}

});

liveDataSwitchMap.observe(this, new Observer() {

@Override

public void onChanged(String s) {

Log.i(TAG, "onChanged2: " + s);

}

});

boolean switchValue = true;

liveDataSwitch.setValue(switchValue);//设置切换条件值

liveData3.setValue(“liveData3”);

liveData4.setValue(“liveData4”);

liveData3、liveData4是两个数据源,有一个判断条件来决定 取哪一个数据 ,这个条件就是liveDataSwitch,如果值为true则取liveData3,false则取liveData4。 Transformations.switchMap()就用于实现这一逻辑,返回值liveDataSwitchMap添加观察者就可以了。 结果如下:

2020-12-06 17:33:53.844 27347-27347/com.hfy.androidlearning I/Lifecycle_Test: switchValue=true

2020-12-06 17:33:53.847 27347-27347/com.hfy.androidlearning I/Lifecycle_Test: onChanged2: liveData3

2020-12-06 17:34:37.600 27628-27628/com.hfy.androidlearning I/Lifecycle_Test: switchValue=false

2020-12-06 17:34:37.602 27628-27628/com.hfy.androidlearning I/Lifecycle_Test: onChanged2: liveData4

(Transformations对LivaData这两个用法和Rxjava简直一毛一样)

2.3.3 观察多个数据 - MediatorLiveData

MediatorLiveData 是 LiveData 的子类,允许合并多个 LiveData 源。只要任何原始的 LiveData 源对象发生更改,就会触发 MediatorLiveData 对象的观察者。

MediatorLiveData mediatorLiveData = new MediatorLiveData<>();

MutableLiveData liveData5 = new MutableLiveData<>();

MutableLiveData liveData6 = new MutableLiveData<>();

//添加 源 LiveData

mediatorLiveData.addSource(liveData5, new Observer() {

@Override

public void onChanged(String s) {

Log.i(TAG, "onChanged3: " + s);

mediatorLiveData.setValue(s);

}

});

//添加 源 LiveData

mediatorLiveData.addSource(liveData6, new Observer() {

@Override

public void onChanged(String s) {

Log.i(TAG, "onChanged4: " + s);

mediatorLiveData.setValue(s);

}

});

//添加观察

mediatorLiveData.observe(this, new Observer() {

@Override

public void onChanged(String s) {

Log.i(TAG, "onChanged5: "+s);

//无论liveData5、liveData6更新,都可以接收到

}

});

liveData5.setValue(“liveData5”);

//liveData6.setValue(“liveData6”);

例如,如果界面中有可以从本地数据库或网络更新的 LiveData 对象,则可以向 MediatorLiveData 对象添加以下源:

  • 与存储在本地数据库中的数据关联的 liveData5

  • 与从网络访问的数据关联的 liveData6

Activity 只需观察 MediatorLiveData 对象即可从这两个源接收更新。 结果如下:

2020-12-06 17:56:17.870 29226-29226/com.hfy.androidlearning I/Lifecycle_Test: onChanged3: liveData5

2020-12-06 17:56:17.870 29226-29226/com.hfy.androidlearning I/Lifecycle_Test: onChanged5: liveData5

(Transformations也是对MediatorLiveData的使用。)

LiveData的使用就讲完了,下面开始源码分析。

3、源码分析

======

前面提到 LiveData几个特点,能感知生命周期状态变化、不用手动解除观察等等,这些是如何做到的呢?

3.1 添加观察者


LiveData原理是观察者模式,下面就先从LiveData.observe()方法看起:

/**

  • 添加观察者. 事件在主线程分发. 如果LiveData已经有数据,将直接分发给observer。

  • 观察者只在LifecycleOwner活跃时接受事件,如果变为DESTROYED状态,observer自动移除。

  • 当数据在非活跃时更新,observer不会接收到。变为活跃时 将自动接收前面最新的数据。

  • LifecycleOwner非DESTROYED状态时,LiveData持有observer和 owner的强引用,DESTROYED状态时自动移除引用。

  • @param owner 控制observer的LifecycleOwner

  • @param observer 接收事件的observer

*/

@MainThread

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

assertMainThread(“observe”);

if (owner.getLifecycle().getCurrentState() == DESTROYED) {

// LifecycleOwner是DESTROYED状态,直接忽略

return;

}

//使用LifecycleOwner、observer 组装成LifecycleBoundObserver,添加到mObservers中

LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);

ObserverWrapper existing = mObservers中.putIfAbsent(observer, wrapper);

if (existing != null && !existing.isAttachedTo(owner)) {

//!existing.isAttachedTo(owner)说明已经添加到mObservers中的observer指定的owner不是传进来的owner,就会报错“不能添加同一个observer却不同LifecycleOwner”

throw new IllegalArgumentException(“Cannot add the same observer”

  • " with different lifecycles");

}

if (existing != null) {

return;//这里说明已经添加到mObservers中,且owner就是传进来的owner

}

owner.getLifecycle().addObserver(wrapper);

}

首先是判断LifecycleOwner是DESTROYED状态,就直接忽略,不能添加。接着使用LifecycleOwner、observer 组装成LifecycleBoundObserver包装实例wrapper,使用putIfAbsent方法observer-wrapper作为key-value添加到观察者列表mObservers中。(putIfAbsent意思是只有列表中没有这个observer时才会添加。)

然后对添加的结果进行判断,如果mObservers中已经存在此observer key,但value中的owner不是传进来的owner,就会报错“不能添加同一个observer却是不同LifecycleOwner”。如果是相同的owner,就直接returne。

最后用LifecycleOwner的Lifecycle添加observer的封装wrapper。

另外,再看observeForever方法:

@MainThread

public void observeForever(@NonNull Observer<? super T> observer) {

assertMainThread(“observeForever”);

AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);

ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);

if (existing instanceof LiveData.LifecycleBoundObserver) {

throw new IllegalArgumentException(“Cannot add the same observer”

  • " with different lifecycles");

}

if (existing != null) {

return;

}

wrapper.activeStateChanged(true);

}

和observe()类似,只不过 会认为观察者一直是活跃状态,且不会自动移除观察者。

3.2 事件回调


LiveData添加了观察者LifecycleBoundObserver,接着看如何进行回调的:

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() { //至少是STARTED状态

return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);

}

@Override

public void onStateChanged(@NonNull LifecycleOwner source,

@NonNull Lifecycle.Event event) {

if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {

removeObserver(mObserver);//LifecycleOwner变成DESTROYED状态,则移除观察者

return;

}

activeStateChanged(shouldBeActive());

}

@Override

boolean isAttachedTo(LifecycleOwner owner) {

return mOwner == owner;

}

@Override

void detachObserver() {

mOwner.getLifecycle().removeObserver(this);

}

}

LifecycleBoundObserver是LiveData的内部类,是对原始Observer的包装,把LifecycleOwner和Observer绑定在一起。当LifecycleOwner处于活跃状态,就称 LifecycleBoundObserver是活跃的观察者。

它实现自接口LifecycleEventObserver,实现了onStateChanged方法。上一篇Lifecycle中提到onStateChanged是生命周期状态变化的回调。

在LifecycleOwner生命周期状态变化时 判断如果是DESTROYED状态,则移除观察者。LiveData自动移除观察者特点就来源于此。 如果不是DESTROYED状态,将调用父类ObserverWrapper的activeStateChanged()方法处理 这个生命周期状态变化,shouldBeActive()的值作为参数,至少是STARTED状态为true,即活跃状态为true。

private abstract class ObserverWrapper {

void activeStateChanged(boolean newActive) {

if (newActive == mActive) {

return;//活跃状态 未发生变化时,不会处理。

}

mActive = newActive;

boolean wasInactive = LiveData.this.mActiveCount == 0;//没有活跃的观察者

LiveData.this.mActiveCount += mActive ? 1 : -1;//mActive为true表示变为活跃

if (wasInactive && mActive) {

onActive();//活跃的观察者数量 由0变为1

}

if (LiveData.this.mActiveCount == 0 && !mActive) {

onInactive(); //活跃的观察者数量 由1变为0

}

if (mActive) {

dispatchingValue(this);//观察者变为活跃,就进行数据分发

}

}

}

ObserverWrapper也是LiveData的内部类。mActive是ObserverWrapper的属性,表示此观察者是否活跃。如果活跃状态 未发生变化时,不会处理。

LiveData.this.mActiveCount == 0 是指 LiveData 的活跃观察者数量。活跃的观察者数量 由0变为1、由1变为0 会分别调用LiveData的 onActive()、onInactive()方法。这就是前面提到的扩展使用的回调方法。

最后观察者变为活跃,就使用LiveData的dispatchingValue(observerWrapper)进行数据分发:

void dispatchingValue(@Nullable ObserverWrapper initiator) {

if (mDispatchingValue) {

mDispatchInvalidated = true;//如果当前正在分发,则分发无效,return

return;

}

mDispatchingValue = true; //标记正在分发

do {

mDispatchInvalidated = false;

if (initiator != null) {

considerNotify(initiator); //observerWrapper不为空,使用considerNotify()通知真正的观察者

initiator = null;

} else { //observerWrapper为空,遍历通知所有的观察者

for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =

mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {

considerNotify(iterator.next().getValue());

if (mDispatchInvalidated) {

break;

}

}

}

} while (mDispatchInvalidated);

mDispatchingValue = false;

}

如果当前正在分发,则分发无效;observerWrapper不为空,就使用considerNotify()通知真正的观察者,observerWrapper为空 则遍历通知所有的观察者。 observerWrapper啥时候为空呢?这里先留个疑问。 继续看considerNotify()方法:

private void considerNotify(ObserverWrapper observer) {

if (!observer.mActive) {

return; //观察者非活跃 return

}

//若当前observer对应owner非活跃,就会再调用activeStateChanged方法,并传入false,其内部会再次判断

if (!observer.shouldBeActive()) {

observer.activeStateChanged(false);

return;

}

if (observer.mLastVersion >= mVersion) {

return;

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

以前一直是自己在网上东平西凑的找,找到的东西也是零零散散,很多时候都是看着看着就没了,时间浪费了,问题却还没得到解决,很让人抓狂。

后面我就自己整理了一套资料,还别说,真香!

资料有条理,有系统,还很全面,我不方便直接放出来,大家可以先看看有没有用得到的地方吧。

系列教程图片

2020Android复习资料汇总.png

flutter

NDK

设计思想开源框架

微信小程序

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

…(img-vkIiKYU6-1713396992371)]

[外链图片转存中…(img-kOiLZhLK-1713396992373)]

[外链图片转存中…(img-qP1CVyCy-1713396992374)]

[外链图片转存中…(img-AWpega3B-1713396992375)]

[外链图片转存中…(img-6sUS9tap-1713396992376)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

以前一直是自己在网上东平西凑的找,找到的东西也是零零散散,很多时候都是看着看着就没了,时间浪费了,问题却还没得到解决,很让人抓狂。

后面我就自己整理了一套资料,还别说,真香!

资料有条理,有系统,还很全面,我不方便直接放出来,大家可以先看看有没有用得到的地方吧。

[外链图片转存中…(img-qz9sDEWi-1713396992377)]

[外链图片转存中…(img-n8OYUA23-1713396992377)]

[外链图片转存中…(img-UchM0nUk-1713396992378)]

[外链图片转存中…(img-gNxhivhE-1713396992379)]

[外链图片转存中…(img-Bu6uVKEI-1713396992380)]

[外链图片转存中…(img-irSy7LDY-1713396992381)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 11
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值