Jetpack架构组件 四-- LiveData使用和原理
前言
在 LiveData 出现之前,一般状态分发我们使用EventBus或者RxJava,这些都很容易出现内存泄漏问题,而且需要我们手动管理生命周期。而 LiveData 则规避了这些问题,LiveData 是一个持有 Activity、Fragment 生命周期的数据容器。当数据源发生变化的时候,通知它的观察者更新 UI 界面。同时它可以只通知处于 Active 状态的观察者更新界面。所以不用担心内存泄漏问题。一般来说,LiveData很少单独使用,它更多的和Android Jetpack的其他组件搭配使用,比如和ViewModel。这篇文章就来介绍LiveData的使用。
1、 什么是LiveData
LiveData 是一个可观察的数据持有者,和常规的observable不同,LiveData 是可以感知生命周期的,也就是说它能够在 Activity、Fragment、Service 中正确的处理生命周期。
LiveData 的数据源一般是 ViewModel,也可以是其它可以更新 LiveData 的组件。当数据更新后,LiveData 就会通知它的所有观察者,比如 Activity。与 RxJava 的方法不同的是,LiveData 可以不通知所有观察者,它可以只通知处于 Active 状态的观察者。这对于Activity 和 Service 特别有用,因为它们可以安全地观察 LiveData 对象而不用担心内存泄漏的问题。还有一点需要注意的是一旦观察者重新恢复到活跃状态,它将会重新收到 LiveData 的最新数据。
2、 LiveData的基本使用
LiveData 是一个抽象类,它的最简单的实现类为 MutableLiveData,使用方法如下所示:
public class MainActivity extends AppCompatActivity {
MutableLiveData<String> mutableLiveData = new MutableLiveData<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mutableLiveData.observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable final String s) {
Log.d("MainActivity", "onChanged:" s);
}
});
mutableLiveData.postValue("LiveData 基本使用");
}
}
MutableLiveData 的 observe 方法有两个参数分别是 LifecycleOwner 和 Observer<T>
,第一个参数就是MainActivity 本身,第二个参数新建了一个Observer<String>
,在onChanged方法中得到回调。postValue 方法会在主线程中更新数据,运行结果如下所示:
除了 MutableLiveData 的 postValue 方法,还可以使用 setValue 方法,它们之前的区别是,setValue 方法必须在主线程使用,如果是在子线程线程中更新 LiveData,则可以使用 postValue 方法。
3、 更改LiveData中的数据
如果我们想要在 LiveData 对象分发给观察者之前对其中存储的值进行更改,可以使用 Transformations.map() 和Transformations.switchMap(),下面通过简单的例子来讲解它们。
2.1 Transformations.map()
如果想要在 LiveData 对象分发给观察者之前对其中存储的值进行更改,可以使用Transformations.map()。
public class MainActivity extends AppCompatActivity {
MutableLiveData<String> mutableLiveData = new MutableLiveData<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mutableLiveData.observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable final String s) {
Log.d("MainActivity", "onChanged:" s);
}
});
LiveData transformedLiveData = Transformations.map(mutableLiveData, new Function<String, Object>() {
@Override
public Object apply(String name) {
return name " Transformations.map 的使用";
}
});
transformedLiveData.observe(this, new Observer() {
@Override
public void onChanged(@Nullable Object o) {
Log.d("MainActivity", "onChanged2:" o.toString());
}
});
mutableLiveData.postValue("LiveData 基本使用");
}
}
通过Transformations.map(),在mutableLiveData的基础上又加上了字符串" Transformations.map 的使用"。
运行结果如下所示:
2.2 Transformations.switchMap()
public class MainActivity extends AppCompatActivity {
private MutableLiveData<String> mutableLiveData1;
private MutableLiveData<String> mutableLiveData2;
private MutableLiveData<Boolean> liveDataSwitch;
private LiveData transformedLiveData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mutableLiveData1 = new MutableLiveData<>();
mutableLiveData2 = new MutableLiveData<>();
liveDataSwitch = new MutableLiveData<>();
transformedLiveData= Transformations.switchMap(liveDataSwitch, new Function<Boolean, LiveData<String>>() {
@Override
public LiveData<String> apply(Boolean input) {
if (input) {
return mutableLiveData1;
} else {
return mutableLiveData2;
}
}
});
transformedLiveData.observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable final String s) {
Log.d("MainActivity", "onChanged:" s);
}
});
liveDataSwitch.postValue(false);
mutableLiveData1.postValue("Transformations.switchMap 用法1");
mutableLiveData2.postValue("Transformations.switchMap 用法2");
}
}
MutableLiveData<Boolean>()
用来控制切换,当 liveDataSwitch 的值为true时返回mutableLiveData1,否则返回 mutableLiveData2。
2.3 合并多个LiveData数据源
MediatorLiveData 继承自 mutableLiveData,它可以将多个 LiveData 数据源集合起来,可以达到一个组件监听多个 LiveData 数据变化的目的,用法如下所示:
public class MainActivity extends AppCompatActivity {
private MutableLiveData<String> mutableLiveData1;
private MutableLiveData<String> mutableLiveData2;
private MediatorLiveData mediatorLiveData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mutableLiveData1 = new MutableLiveData<>();
mutableLiveData2 = new MutableLiveData<>();
mediatorLiveData = new MediatorLiveData<String>();
mediatorLiveData.addSource(mutableLiveData1, new Observer() {
@Override
public void onChanged(@Nullable Object o) {
Log.d("MainActivity", "onChanged1:" o.toString());
}
});
mediatorLiveData.addSource(mutableLiveData2, new Observer() {
@Override
public void onChanged(@Nullable Object o) {
Log.d("MainActivity", "onChanged2:" o.toString());
}
});
mediatorLiveData.observe(this, new Observer() {
@Override
public void onChanged(@Nullable Object o) {
Log.d("MainActivity", "onChanged:" o.toString());
}
});
mutableLiveData1.postValue("mutableLiveData 1");
mutableLiveData2.postValue("mutableLiveData 2");
mediatorLiveData.postValue("mediatorLiveData 使用");
}
}
通过 MediatorLiveData 的 addSource 将两个 MutableLiveData 合并到一起,这样当任何一个 MutableLiveData数据发生变化时,MediatorLiveData 都可以感知到,运行结果如下所示:
4、LiveData源码解析
由于 LiveData 是一个 abstract class,我们不能直接生成他的实例。官方有提供他的实现类MutableLiveData
,代码如下所示:
public class MutableLiveData<T> extends LiveData<T> {
...
// 可以在子线程中调用
@Override
public void postValue(T value) {
super.postValue(value);
}
// 必须在主线程中调用
@Override
public void setValue(T value) {
super.setValue(value);
}
}
创建了 LiveData 后,需要通过 observe 方法或者 observeForever 方法设置一个观察者,这个观察者接口就是Observer,代码如下:
public interface Observer<T> {
// 这个回调发生在主线程
void onChanged(T t);
}
LiveData 的添加观察者的代码如下:
public abstract class LiveData<T> {
...
// 只有onStart之后,onStop之前,对数据的修改才会触发 observer.onChanged()
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
}
// 无论何时,只要数据发生改变,就会触发 observer.onChanged()
public void observeForever(@NonNull Observer<? super T> observer) {
}
...
}
observeForever 的实现跟 observe 是类似的,这里我们重点看一下 observe()的实现过程,代码如下:
// 只能在主线程调用
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
//如当前UI的状态的是DESTROYED,就不绑定这个回调了
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
//创建生命周期感知的观察者包装类(把注册进来的observer包装成一个具有生命周边边界的观察者)
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
//接着会判断该观察是否已经注册过了,如果是则抛异常, 对应观察者只能与一个owner绑定,不允许重复注册
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
" with different lifecycles");
}
if (existing != null) {
return;
}
//把wrapper与Activity/Fragment的生命周期,建立关系,
//当UI的生命周期发生变化的时候,就会去回调wrapper中的onStateChanged方法
owner.getLifecycle().addObserver(wrapper);
}
4.2 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() {
/*
观察者是否活跃就等于mOwner的状态是否大于等于STARTED;
如果页面当前不可见,你发送了一条消息,此时是不会被分发的,
可以避免后台任务抢占资源,当页面恢复可见才会分发。
*/
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
// Activity/Fragment的生命周期变化会回调此方法。
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
// 如果当接收到DESTROYED的事件会自动解除跟owner的绑定,避免内存泄露
if (currentState == DESTROYED) {
removeObserver(mObserver);
return;
}
Lifecycle.State prevState = null;
while (prevState != currentState) {
prevState = currentState;
//说明宿主的状态发生了变化,此时会判断宿主是否处于活跃状态
activeStateChanged(shouldBeActive());
currentState = mOwner.getLifecycle().getCurrentState();
}
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
4.3 ObserverWrapper
状态变更后,如果观察者处于活跃状态会触发数据的分发流程
private abstract class ObserverWrapper {
final Observer<? super T> mObserver;
boolean mActive;
//ObserverWrapper在每次注册的时候都会重新new,所以mLastVersion每次都是-1开始。
int mLastVersion = START_VERSION;
ObserverWrapper(Observer<? super T> observer) {
mObserver = observer;
}
abstract boolean shouldBeActive();
boolean isAttachedTo(LifecycleOwner owner) {
return false;
}
void detachObserver() {
}
void activeStateChanged(boolean newActive) {
//当前的生命周期和上一次的生命周期状态,是否发生变化,没有发生变化,就直接返回。
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive;
// 更新活跃值 活跃1 非活跃-1
changeActiveCounter(mActive ? 1 : -1);
if (mActive) {
// 如果是活跃状态,分发值
dispatchingValue(this);
}
}
}
changeActiveCounter 方法代码如下:
@MainThread
void changeActiveCounter(int change) {
// 上一次的活跃数
int previousActiveCount = mActiveCount;
// 当前活跃数
mActiveCount = change;
if (mChangingActiveState) {
return;
}
mChangingActiveState = true;
try {
while (previousActiveCount != mActiveCount) {
// 从不活跃变为活跃状态,需要回调 onActive方法
boolean needToCallActive = previousActiveCount == 0 && mActiveCount > 0;
// 从活跃状态变为不活跃状体,需要回调onInactive方法
boolean needToCallInactive = previousActiveCount > 0 && mActiveCount == 0;
previousActiveCount = mActiveCount;
if (needToCallActive) {
onActive();
} else if (needToCallInactive) {
onInactive();
}
}
} finally {
mChangingActiveState = false;
}
}
dispatchingValue(this)数据分发流程控制:(内部执行considerNotify(initiator)方法),这个方法我们后面分析。
4.4 setValue 发送数据源码分析
postValue 最终也是调用 setValue 方法,这里就不做分析了,我们主要分析 setValue 方法,代码如下:
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
// 这个mVersion是属于LiveData的,然后只在setValue
// (postValue最终也会调用setValue)的时候会自增1
mVersion ;
// 保存这次变化的数据
mData = value;
// 分发数据
dispatchingValue(null);
}
接下来我们具体分析 dispatchingValue 方法,代码如下:
@SuppressWarnings("WeakerAccess") /* synthetic access */
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
//进入while循环前,设置为true,如果此时另外一个数据发生变化,到了此函数中就直接在上面返回了
mDispatchingValue = true;
do {
//开始for循环前,设置为false,for循环完,也会退出while循环
mDispatchInvalidated = false;
if (initiator != null) {
// 如果传递的观察者不为空,则把数据分发给他自己。
// 这个流程是Activity/Fragment的生命周期发生变化的时候会被触发
considerNotify(initiator);
initiator = null;
} else {
// 遍历集合中所有已注册的的观察者,逐个调用considerNotify,分发数据
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
//这里mDispatchInvalidated 为true,表示在while循环未结束的时候,
// 有其他数据发生变化,并调用了该函数
//在上面的if判断中设置了 mDispatchInvalidated = true,
// 结束本次for循环,没有退出while循环,开始下一次for循环
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
//退出while 后,设置为false,正常处理数据变化
mDispatchingValue = false;
}
这里有两个变量
-
mDispatchingValue 这个变量用来控制,是否进入while 循环,以及while 循环 是否已经结束
-
mDispatchInvalidated 这个变量用来控制for 循环是否要重新开始
看下considerNotify 的函数,调用了之前 LiveData 设置的 observer 的 onChanged 函数,代码如下:
private void considerNotify(ObserverWrapper observer) {
// 观察者当前状态不活跃就不分发
if (!observer.mActive) {
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.
// 如果当前的生命周期是非活跃,就不回调onChanged函数,
// 在LifecycleBoundObserver 中记录状态,当生命周期变为活跃,就回去更新数据
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
// 此处判断观察者接收消息的次数是否大于等于 发送消息的次数(observer被创建之初verison=-1 )
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
// 这里会执行传入的observer的onChanged方法
observer.mObserver.onChanged((T) mData);
}
综上分析:LiveData的粘性事件:
-
-
通过同一个LiveData 在更改数据的时候调用 setValue(postValue 最终也会调用 setValue) 的时候内部维护的 mVersion 会自增1,mVersion 初始值是-1
-
在监听数据变化的时候,即调用 observer 监听的时候,每次内部都会在通过包装类中new ObserverWrapper,内部维护了一个mLastVersion变量,mLastVersion也是初始值为-1,所以注意了,每执行一次 observer 方法内部维护 mLastVersion 都会新创建而变为 -1 ,如果 mLastVersion 小于 mVersion 的时候就表示有新的变化没有回调 observer 的 onChanged 方法。
-
结论所以只要之前有发射过一次数据,那么后面注册的观察者都会接收到最精一次发射过的数据
-
这种情况被称为LiveData的粘性事件
扫描下方二维码关注公众号,获取更多技术干货。
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgfkceb
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01