本文已收录到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专栏] ,第一时间阅览更多干货知识!