初到掘金,人生地不熟,喜欢的朋友,点个赞鼓励下新手呗~
java
参考连接:
https://developer.android.google.cn/topic/libraries/architecture/livedata https://mp.weixin.qq.com/s/ir3DBkGt5mna3RDjTpRFOQ
LiveData是google发布的lifecycle-aware components中的一个组件,除了能实现数据和View的绑定响应以外,它最大的特色就是具有生命周期感知功能
android
LiveData采用了观察者模式,当数据发生变化时,主动通知被观察者 。
架构
因为LiveData会在Activity/Fragment等具备生命周期的lifecycleOwner组件调用onDestory的时候自动解绑,因此解决了可能存在的内存泄漏问题。以前咱们为了不这个问题,通常有注册绑定的地方都要解绑(即注册跟解绑要成对出现),而LiveData利用生命周期感知功能解决了这一问题,能够实现只需关心注册,而解绑会根据生命周期自动进行的功能。
app
当Activity组件处于inactive非活动状态时,它不会收到LiveData数据变化的通知。
less
观察者并不须要手动处理生命周期变化对自身的逻辑的影响,只须要关心如何处理获取到的数据。LiveData可以感知Activity/Fragment等组件的生命周期变化,因此就彻底不须要在代码中告诉LiveData组件的生命周期状态,当数据发生变化时,只在生命周期处于active下通知观察者,而在inactive下,不会通知观察者。
异步
什么意思呢?第一种状况,当观察者处于active活动状态。LiveData基于观察者模式,因此当数据发生变化,观察者可以立刻获取到最新变化;第二种状况,当观察者处于inactive非活动状态。LiveData只能生命周期active下发送数据给观察者。举个例子,当Activity处于后台(inactive)时,LiveData接收到了新的数据,但这时候LiveData并不会通知该Activity,可是当该Activity从新返回前台(active)时会继续接收到最新的数据。一句话归纳,LiveData是粘性的。ide
咱们知道,当你把数据存储在组件中时,当configuration change(好比语言、屏幕方向变化)时,组件会被recreate,然而系统并不能保证你的数据可以被恢复的。当咱们采用LiveData保存数据时,由于数据和组件分离了。当组件被recreate,数据仍是存在LiveData中,并不会被销毁。
源码分析
经过继承LiveData类,而后将该类定义成单例模式,在该类封装监听一些系统属性变化,而后通知LiveData的观察者。
post
LiveData注册的观察者的两种方式:优化
// 这个方法添加的observer会受到owner生命周期的影响,在owner处于active状态时,有数据变化,会通知,
// 当owner处于inactive状态,不会通知,而且当owner的生命周期状态时DESTROYED时,自动removeObserver
public void observe (LifecycleOwner owner, Observer<? super T> observer) // 这个方法添加的observer不存在生命周期概念,只要有数据变化,LiveData都会通知,而且不会自动remove public void observeForever (Observer<? super T> observer) 复制代码
LiveData发布修改的两种方式:
// 这个方法必须在主线程调用
protected void setValue (T value) // 这个方式主要用于在非主线程调用 protected void postValue (T value) 复制代码
LiveData 官方API文档: https://developer.android.google.cn/reference/androidx/lifecycle/LiveData
举个例子:在Activity页面有一TextView,须要展现用户User的信息,User 类定义:
public class User {
public String name;
public int sex;
public User(String name, int sex) {
this.name = name;
this.sex = sex;
}
@Override
public String toString() {
return "User{" +
", name='" + name + '\'' +
", sex='" + sex+ '\'' +
'}';
}
}复制代码
常规的作法:
// 获取User的数据后
mTvUser.setText(user.toString());复制代码
这样作的一个问题,若是获取或者修改User的来源不止一处,那么须要在多个地方更新TextView,而且若是在多处UI用到了User,那么也须要在多处更新。
怎么优化这个问题呢?使用 LiveData。不少时候,LiveData与ViewModel组合使用(ViewModel后续文章会分析),让LiveData持有User 实体,做为一个被观察者,当User改变时,通知全部使用User的观察者自动change。
首先构建一个UserViewModel以下:
public class UserViewModel extends ViewModel {
//声明userLiveData
private MutableLiveData<User> userLiveData;
//获取userLiveData
public LiveData getUserLiveData() {
if(userLiveData == null) {
userLiveData = new MutableLiveData<>();
}
return userLiveData;
}
}复制代码
而后注册观察者:
public class TestActivity extends AppCompatActivity {
private UserViewModel mModel;
private TextView mUserTextView;
@Override
public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);
mModel = ViewModelProviders.of(this).get(UserViewModel.class);
//建立用来更新ui的观察者,重写onChange方法,该方法会在数据发生变化时
//经过LiveData调用观察者的onChange对数据变化响应
final Observer<User> userObserver = new Observer<User>() {
@Override
public void onChanged(@Nullable User user) {
LogUtil.i(TAG, user.toString());
//当收到LiveData发来的新数据时,更新
mUserTextView.setText(user.toString());
}
};
//获取监听User数据的LiveData
LiveData userLiveData = mModel.getUserLiveData();
//注册User数据观察者
userLiveData.observe(this, userObserver);
}
}复制代码
数据源发送改变的时候:
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
User user = new User("zhang san", 1)
//调用LiveData的setValue方法通知观察者数据变化
mModel.getUserLiveData().setValue(user);
}
});复制代码
这样使用到 User 的地方,UI 会自动更新,日志以下:
com.example.cimua I/TestActivity : User{name='zhang san', sex=1}复制代码
好了,LiveData的基本使用就是这么简单~~~
LiveData更多用法能够看官方文档 https://developer.android.google.cn/topic/libraries/architecture/livedata
LiveData是基于观察者模式构建的,因此,咱们分析LiveData的源码主要能够分红两部分:
如今咱们先看看observe()方法,由于observeForever()方法的实现跟observe()是相似的,咱们就不看了,这里只看observe():
// 咱们已经知道,LiveData可以感知生命周期的变化。从传入的第一个参数是LifecycleOwner类型,咱们已经
// 能够知道,原来LiveData是基于Lifecycle架构的基础上扩展的,咱们在前一篇Lifecyle文章中已经分析过
// Lifecyle组件了,LiveData就是封装了特定的LifecycleObserver并将其注册到LifecycleOwner中,用以感知
// 生命周期
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
// 若是LifecycleOwner的生命周期状态已是DESTROYED,例如Activity已经destroy,
// 那么就不必添加观察者,直接返回就能够了
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
// 建立继承了GenericLifecycleObserver的LifecycleBoundObserver,而且将这个LifecycleBoundObserver
// 存进观察者集合mObservers中统一管理
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
// 一个observer对象,只能监听一个LifecycleOwner的生命周期,
// 若是试图监听不一样LifecycleOwner的生命周期,直接抛异常
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
// 调用observe()这个方法添加的observer,只有Activity/Fragment等生命周期组件可见时
// 才会收到数据更新的通知,为了知道何时Activity/Fragment是可见的,这里须要注册到
// Lifecycle中感知生命周期
// 也是由于这个,observe()比observeForever()多了一个参数lifecycleOwner
owner.getLifecycle().addObserver(wrapper);
}复制代码
接着咱们在看看observe()方法中最重要的LifecycleBoundObserver:
private abstract class ObserverWrapper {
final Observer<T> mObserver;
boolean mActive;
int mLastVersion = START_VERSION;
ObserverWrapper(Observer<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;
// LiveData.this.mActiveCount表示处于active状态的observer的数量
// 当mActiveCount大于0时,LiveData处于active状态
// 注意区分observer的active状态和 LiveData 的active状态
boolean wasInactive = LiveData.this.mActiveCount == 0;
LiveData.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive) {
// inactive -> active
onActive();
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
// mActiveCount在咱们修改前等于1,也就是说,LiveData从active
// 状态变到了inactive
onInactive();
}
//若是是active状态,通知观察者数据变化(dispatchingValue方法在下一节发布中分析)
if (mActive) {
// observer从inactive到active,此时客户拿到的数据可能不是最新的,这里须要dispatch
// 关于他的实现,咱们下一节再看
dispatchingValue(this);
}
}
}
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
@NonNull final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<T> observer) {
super(observer);
mOwner = owner;
}
// 这个方法返回的是当前是不是active状态
@Override
boolean shouldBeActive() {
// 只有当生命周期状态是STARTED或者RESUMED时返回true,其余状况返回false
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
// 这个方法是由Lifecycle结构中的mLifecycleRegistry所调用,一旦LifecycleOwner的生命周期
// 发生变化,都会调用到onStateChanged这个方法进行生命周期转换的通知
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
// 上面咱们说过,使用LiveData只须要关心注册,不须要关心什么时候解绑,这里就告诉咱们答案:
// 当生命周期状态为DESTROYED,会自动removeObserver实现解绑,不会致使内存泄露。
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
// 一开始建立LifecycleBoundObserver实例的时候,mActive默认为false,
// 当注册到Lifecycle后,Lifecycle会同步生命周期状态给咱们(也就是回调本方法),
// 不熟悉lifecycle的读者,能够看前一篇讲述Lifecycle的文章
activeStateChanged(shouldBeActive());
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}复制代码
到这里,LiveData的订阅流程就基本分析完了。
上面咱们已经说了,LiveData发布修改有setValue已经postValue两种方式,其中setValue只能在主线程调用,postValue则没有这个限制。
咱们从setValue的分析入手发布流程:
@MainThread
protected void setValue(T value) {
// 判断当前调用线程是不是主线程,若是不是,直接抛IllegalStateException异常
assertMainThread("setValue");
// 每次更新value,都会使mVersion + 1,ObserverWrapper也有一个字段,叫mLastVersion
// 经过比较这两个字段,能够避免重复通知观察者,还能够用于实现LiveData的粘性事件特性(后面会说到)
mVersion++;
// 将此次数据保存在LiveData的mData变量中,mData的值永远是最新的值
mData = value;
// 发布
dispatchingValue(null);
}复制代码
接着再看看dispatchingValue方法:
// 若是参数initiator为null的话,表示要将新数据发布通知给全部observer
// 若是参数不为null的话,表示只通知给传入的观察者initiator
private void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
// 在observer的回调里面又触发了数据的修改
// 设置mDispatchInvalidated为true后,可让下面的循环知道
// 数据被修改了,从而开始一轮新的迭代。
//
// 比方说,dispatchingValue -> observer.onChanged -> setValue -> dispatchingValue
// 这里return的是后面那个dispatchingValue,而后在第一个
// dispatchingValue会从新遍历全部的observer,并调用他们的onChanged。
//
// 若是想避免这种状况,能够在回调里面使用 postValue 来更新数据
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
// 调用 observer.onChanged()
considerNotify(initiator);
initiator = null;
} else {
// initiator不为空,遍历mObservers集合,试图通知全部观察者
for (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
// 某个客户在回调里面更新了数据,break后,这个for循环会从新开始
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}复制代码
看过我那篇 lifecycle 源码分析的读者应该对 dispatchingValue 处理循环调用的方式很熟悉了。以这里为例,为了防止循环调用,咱们在调用客户代码前先置位一个标志(mDispatchingValue),结束后再设为 false。若是在回调里面又触发了这个方法,能够经过 mDispatchingValue 来检测。
检测到循环调用后,再设置第二个标志(mDispatchInvalidated),而后返回。返回又会回到以前的调用,前一个调用经过检查 mDispatchInvalidated,知道数据被修改,因而开始一轮新的迭代。
接着继续看considerNotify方法:
private void considerNotify(ObserverWrapper observer) {
// 若是observer的状态不是active,那么不向该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.
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
// 上面的源码分析,咱们知道每一次setValue或者postValue的调用都会是mVersion自增1,
// mLastVersion的做用是为了与mVersion做比较,这个比较做用主要有两点:
// 1.若是说mLastVersion >= mVersion,证实这个观察者已经接受过本次发布事件通知,不须要重复通知了,直接返回
// 2.实现粘性事件。好比有一个数据(LiveData)在A页面setValue()以后,则该数据(LiveData)中的
// 全局mVersion+1,也就标志着数据版本改变,而后再从A页面打开B页面,在B页面中开始订阅该LiveData,
// 因为刚订阅的时候内部的数据版本都是从-1开始,此时内部的数据版本就和该LiveData全局的数据
// 版本mVersion不一致,根据上面的原理图,B页面打开的时候生命周期方法一执行,则会进行notify,
// 此时又同时知足页面是从不可见变为可见、数据版本不一致等条件,因此一进B页面,B页面的订阅就会被响应一次
if (observer.mLastVersion >= mVersion) {
return;
}
// 设置mLastVersion = mVersion,以避免重复通知观察者
observer.mLastVersion = mVersion;
// 这里就最终调用了咱们一开始经过observe()方法传入的observer中的onChange()方法
// 即新数据被发布给了observer
observer.mObserver.onChanged((T) mData);
}复制代码
setValue的分析就到此为止了~
在setValue的基础上,分析postValue就比较简单了:
private final Runnable mPostValueRunnable = new Runnable() {
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
//noinspection unchecked
setValue((T) newValue);
}
};
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
// 经过handler将mPostValueRunnable分发到主线程执行,其实最终执行的也是setValue方法
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}复制代码
LiveData的源码就分析这么多了,更详细就须要到android源码里面找了。
将LiveData的源码抽象为一张流程图来展现,下面的其余问题均可以在这张图中找到答案:
lifecycle-aware compents的核心就是生命周期感知,要明白LiveData为何能感知生命周期,就要知道Google的这套生命周期感知背后的原理是什么,下面是我基于以前lifeycycle这套东西刚出来时候对源码进行的一个分析总结(如今的最新代码可能和以前有点出入,可是原理上基本是同样的):
首先Activity/Fragment是LifecycleOwner(26.1.0以上的support包中Activity已经默认实现了LifecycleOwner接口),内部都会有一个LifecycleRegistry存放生命周期State、Event等。而真正核心的操做是,每一个Activity/Fragment在启动时都会自动添加进来一个Headless Fragment(无界面的Fragment),因为添加进来的Fragment与Activity的生命周期是同步的,因此当Activity执行相应生命周期方法的时候,同步的也会执行Headless Fragment的生命周期方法,因为这个这个Headless Fragment对咱们开发者来讲是隐藏的,它会在执行本身生命周期方法的时候更新Activity的LifecycleRegistry里的生命周期State、Event, 而且notifyStateChanged来通知监听Activity生命周期的观察者。这样就到达了生命周期感知的功能,因此实际上是一个隐藏的Headless Fragment来实现了监听者能感知到Activity的生命周期。
基于这套原理,只要LiveData注册了对Activity/Fragment的生命周期监听,也就拥有了感知生命周期的能力。
因为LiveData会在Activity/Fragment等具备生命周期的lifecycleOwner onDestory的时候自动解绑,因此解决了可能存在的内存泄漏问题。以前咱们为了不这个问题,通常有注册绑定的地方都要解绑,而LiveData利用生命周期感知功能解决了这一问题。
咱们能够知道,当Activity/Fragment的生命周期发生改变时,LiveData中的监听都会被回调,因此避免内存泄漏就变得十分简单,能够看上图,当LiveData监听到Activity onDestory时则removeObserve,使本身与观察者自动解绑。这样就避免了内存泄漏。
咱们一般在一个异步任务回来后须要更新View,而此时页面可能已经被回收,致使常常会出现View空异常,而LiveData因为具有生命周期感知功能,在界面可见的时候才会进行响应,如界面更新等,若是在界面不可见的时候发起notify,会等到界面可见的时候才进行响应更新。因此就很好的解决了空异常的问题。
所谓粘性,也就是说消息在订阅以前发布了,订阅以后依然能够接受到这个消息,像EventBus实现粘性的原理是,把发布的粘性事件暂时存在全局的集合里,以后当发生订阅的那一刻,遍历集合,将事件拿出来执行。
而LiveData之因此自己就是粘性的,结合上面的原理图咱们来分析一下,好比有一个数据(LiveData)在A页面setValue()以后,则该数据(LiveData)中的全局mVersion+1,也就标志着数据版本改变,而后再从A页面打开B页面,在B页面中开始订阅该LiveData,因为刚订阅的时候内部的数据版本都是从-1开始,此时内部的数据版本就和该LiveData全局的数据版本mVersion不一致,根据上面的原理图,B页面打开的时候生命周期方法一执行,则会进行notify,此时又同时知足页面是从不可见变为可见、数据版本不一致等条件,因此一进B页面,B页面的订阅就会被响应一次。这就是所谓的粘性,A页面在发消息的时候B页面是还没建立还没订阅该数据的,可是一进入B页面一订阅,以前在A中发的消息就会被响应。
初到掘金,人生地不熟,喜欢的朋友,点个赞鼓励下新手呗~