本文已收录到 GitHub/Android-Notes 中,这里有 Android 进阶成长知识体系笔记,有志同道合的朋友,关注公众号 [小尘Android专栏] 跟我一起成长。
前言
Jetpack 是一个由多个库组成的套件,可帮助开发者遵循最佳做法,减少样板代码。如果项目采用 MVVM 架构,那么 Jetpack 里面的架构相关的组件就是为MVVM 量身定制的,而且现在面试Jetpack也是必问项,但是很多开发者对Jetpack中的一些核心组件都只停留在会用的阶段,对其原理及源码却是一知半解甚至根本没了解过,因此整理了一个系列来帮助有需要的小伙伴理解Jetpack设计思想和原理。
正文
LiveData是什么
LiveData,它是一个数据持有类,它内部可以持有一个任意类型的对象。LiveData采用了观察者模式,观察者可观察其持有的对象,只要对象一发生变化,就会通知并将持有对象回调给观察者。同时LiveData的观察者还具备感知组件(Activity、Fragment等)生命周期变化的能力,当组件的生命周期处于不同的状态时,能作出相对应的处理。
LiveData的基本使用
LiveData的基本使用示例:
public class MainActivity extends AppCompatActivity {
//LiveData是抽象类 MutableLiveData是其子类
//所以我们在使用的时候都是使用MutableLiveData
//对象所声明的泛型<String>就是当前这个LiveData所持有的对象的类型,可以是任意类型的对象
MutableLiveData<String> liveData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
liveData = new MutableLiveData<>();
//注册观察者
liveData.observe(this, new Observer<String>() {
@Override
//s就是LiveData持有的数据
public void onChanged(String s) {
Toast.makeText(MainActivity.this,s,Toast.LENGTH_LONG).show();
}
});
}
/**
* 发送通知
* @param view
*/
public void sendMessage(View view) {
//改变LiveData持有的数据
liveData.setValue("aaaaaaaaaaaa");
}
}
当我们通过点击事件调用liveData.setValue("")的时候,就会改变LiveData所持有的数据,这个LiveData对象中的观察者就会被回调,同时会将持有的数据传给观察者,自然观察者中的业务逻辑也会被调用。而且要注意,LiveData提供了两个改变持有数据的方法setValue()以及postValue(),那么他们的区别是什么呢?我们可以先略微看下源码:
public abstract class LiveData<T> {
...省略...
//切换线程的Runnable
private final Runnable mPostValueRunnable = new Runnable() {
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
//最终还是调用setValue
setValue((T) newValue);
}
};
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
//当调用postValue的时候不管当前是什么线程,都直接切换到主线程
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
@MainThread
protected void setValue(T value) {
//当调用setValue的时候,会一开始判断当前是否是在主线程中调用,
//如果不是就直接抛出异常,由此可见setValue仅限于主线程调用
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
private static void assertMainThread(String methodName) {
if (!ArchTaskExecutor.getInstance().isMainThread()) {
throw new IllegalStateException("Cannot invoke " + methodName + " on a background"
+ " thread");
}
}
...省略...
}
当调用setValue()的时候,会一开始判断当前是否是在主线程中调用,如果不是就直接抛出异常,由此可见setValue()仅限于主线程调用。而当调用postValue()的时候,不管当前是什么线程,都直接切换到主线程再执行setValue()方法,所以通过源码可以很明显的看出,setValue()是在主线程中用的,而postValua()是在子线程中用的。
而且通过以上的内容我们可以初步推断出以下图中内容:
当我们通过两个改变数据源的方法进行数据更新的时候,会遍历所有的观察者,然后回调其方法。但事实真的如此简单嘛?在后面的内容中我们会得到答案!
LiveData的使用场景分析
1、网络请求回调
代码示例:
//网络请求数据通过Handler来更新UI
public void handlerTest(){
final Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
responseContentView.setText(msg.obj.toString());
}
};
new Thread(new Runnable() {
@Override
public void run() {
try {
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
.get()
.url("https://v.juhe.cn/historyWeather/citys")
.build();
Call call = okHttpClient.newCall(request);
call.clone().execute();
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String res = response.body().string();
Message msg = new Message();
msg.obj = res;
msg.what = 1;
handler.sendMessage(msg);
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
以上代码作为Android开发者看着肯定会很眼熟,当我们进行网络加载数据时,很久以前都是通过Handler来进行UI更新的。
//网络请求数据通过LiveData来更新UI
public void liveDataTest(){
final MutableLiveData<String> liveData = new MutableLiveData<>();
liveData.observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
//responseContentView.setText(s);
Toast.makeText(MainActivity.this,s,Toast.LENGTH_LONG).show();
}
});
new Thread(new Runnable() {
@Override
public void run() {
try {
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
.get()
.url("https://v.juhe.cn/historyWeather/citys")
.build();
Call call = okHttpClient.newCall(request);
call.clone().execute();
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String res = response.body().string();
//postValue是子线程改变LiveData所持有的数据专用的
liveData.postValue(res);
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
大家会发现,通过LiveData我们同样能达到Handler的效果,以上代码大家可以自行去进行测试。那么问题来了,既然已经有了Handler,然后LiveData的作用看起来和Handler类似,LiveData的存在必要是什么?既生瑜何生亮?自然是“亮”的能力与优势要比“瑜”突出,这一点我们从下面组件通信的使用内容中就可以得出结论。
2、组件通信
//LiveData的管理器
public class LiveDataBus {
private static LiveDataBus liveDataBus = new LiveDataBus();
public Map<String, MutableLiveData<Object>> bus;
private LiveDataBus(){
bus = new HashMap<>();
}
public static LiveDataBus getInstance(){
return liveDataBus;
}
/**
* 添加和取LiveData对象
* @param key
* @param clazz
* @param <T>
* @return
*/
public <T> MutableLiveData<T> putAndGetLiveData(String key,Class<T> clazz){
if(key!=null && !bus.containsKey(key)){
bus.put(key,new MutableLiveData<Object>());
}
return (MutableLiveData<T>) bus.get(key);
}
}
封装好了之后,只要我们在不同的组件中持有同一个LiveData对象就可以传数据以及通信了。代码如下:
public class MainActivity extends AppCompatActivity {
MutableLiveData<String> liveData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建一个LiveData对象,并放到LiveData管理器的Map中
liveData = LiveDataBus.getInstance().putAndGetLiveData("lisan",String.class);
liveData.observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
Toast.makeText(MainActivity.this,s,Toast.LENGTH_LONG).show();
}
});
}
}
在NextActivity中获取到同一个LiveData对象,然后通过setValue改变其所持有的数据,那么在MainActivity里面的注册的观察者就会被通知(回调)。
public class NextActivity extends AppCompatActivity {
MutableLiveData liveData;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_next);
liveData = LiveDataBus.getInstance().putAndGetLiveData("lisan",String.class);
}
public void sendMessage(View view) {
liveData.setValue("NextActivty里面发送了一个通知");
}
}
当大家真正去跑一下以上代码的时候,会发现一个明显的问题,当我们在NextActivity中改变数据源的时候,MainActivity中的观察者并不能立马被回调。这是为什么呢?其实在用LiveData的时候,我们必须要遵循一个规则,那就是观察者只有在其所在的Activity(或其他组件)是可见状态的时候才能被回调,所以当我们在NextActivity发送通知时,MainActivity中的观察者并不能立马收到(因为那时的MainActivity是不可见的状态),只有当MainActivity可见的时候才能收到通知
这就是LiveData的神奇之处,也是LiveData之所以能取代一众事件分发框架的原因(包括Handler)。那为什么会这样呢,这就要归功于Lifecycle了,下面我们会分析Lifecycle的作用以及在LiveData中的作用。详细可看我之前这么Lifecycle的讲解!
3、调用系统相机、广播等
4、与ViewModel、ROOM等配合使用
LiveData源码解读
注册观察者代码解析:
liveData.observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
//responseContentView.setText(s);
Log.e("MainActivity------>",s);
}
});
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
//判断当前组件的生命周期是否已经结束,如果已经结束,就直接返回
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
//将组件和观察者进行包装 这样就能让观察者更好的绑定组件
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
//包装好的类封装到一个容器中key=观察者,value=包装类
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;
}
//将上面的包装类作为观察者注册给Lifecycle,
//说明包装类实现了Lifecycle的观察者方法,也就能够感知到组件的生命周期了
owner.getLifecycle().addObserver(wrapper);
}
接下来看看组件和LiveData观察者的包装类: 为了以后的扩展,定义了一个抽象类。
private abstract class ObserverWrapper {
//观察者
final Observer<? super T> mObserver;
boolean mActive;
//版本号,防止观察者重复收到消息或通知
int mLastVersion = START_VERSION;
ObserverWrapper(Observer<? super T> observer) {
mObserver = observer;
}
abstract boolean shouldBeActive();
boolean isAttachedTo(LifecycleOwner owner) {
return false;
}
void detachObserver() {
}
//当绑定的组件的生命周期发生变化的时候 通过这个API进行事件分发
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive;
boolean wasInactive = LiveData.this.mActiveCount == 0;
LiveData.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive) {
onActive();
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
onInactive();
}
if (mActive) {
dispatchingValue(this);
}
}
}
具体实现:
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
//组件(LiveData所在的Activity)
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
//当前的Activity状态是否是可见的,这里回顾Lifecycle的状态机
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
//实现GenericLifecycleObserver接口的回调,组件生命周期发生改变就会回调
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
//为了避免造成内存泄漏 Activity生命周期结束的好把观察者移除掉
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
//进行分发给观察者
activeStateChanged(shouldBeActive());
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
事件分发的会调用下面这个昂发
@SuppressWarnings("WeakerAccess") /* synthetic access */
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
//组件生命周期回调的时候走if里面
if (initiator != null) {
//回调绑定组件的这个观察者
considerNotify(initiator);
initiator = null;
} else {
//setValue和postValue走这里
//遍历容器中所有的观察者,拿出来传入considerNotify方法
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
private void considerNotify(ObserverWrapper observer) {
//判断观察者所绑定的组件是否处于可见状态,如果不就先不执行
if (!observer.mActive) {
return;
}
//双重判断
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
//判断版本号是否同步,这个会单独讲
if (observer.mLastVersion >= mVersion) {
return;
}
//同步版本号
observer.mLastVersion = mVersion;
//noinspection unchecked
//回调观察者
observer.mObserver.onChanged((T) mData);
}
到这里为止基本LiveData观察者被组件的生命周期变化回调的流程就走完了。接下来就是LiveData中setValue()方法执行的时候是如何被调用观察者的:
@MainThread
protected void setValue(T value) {
//判断是否当前是主线程
assertMainThread("setValue");
//LiveData的版本号+1
mVersion++;
//保存设置进来的对象
mData = value;
//调用观察者(下面的流程就不了,上面已经走完了)
dispatchingValue(null);
}
mVersion和observer.mLastVersion是怎么一回事呢?假设我AActivity中注册了一个观察者,如果AActivity不停的在活跃与不活跃之间进行切换,那么considerNotify()方法就一直会被调用,但是实际上我们并没有发布新的通知,或者改变LiveData持有的对象,这个时候观察者就没必要被回调,所以通过一下代码进行拦截:
if (observer.mLastVersion >= mVersion) {
return;
}
说白了LiveData中的观察者只有在数据发生改变之后才应该被回调,所以不管观察者的生命周期变化了多少次,只要数据没变化,就不需要进行回调。
到此,LiveData和Lifecycle的源码就差不多了。
如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙: 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。微信搜索公众号 [小尘Android专栏] ,第一时间阅读更多干货知识!