LiveData介绍
LiveData 是一个可以被观察的数据持有类,它可以感知 Activity、Fragment或Service 等组件的生命周期。在底层数据更改时通知视图,言外之意就是数据一经更改,就去通知视图去更新数据。
LiveData优点
- 实时数据刷新,实时更新UI
- 避免出现内存泄漏问题
- 避免了由Activity处于stop状态而引起的崩溃
- 屏幕发生旋转或回收时也能立即取到数据
- 避免了界面由生命周期而出现的问题
LiveData使用步骤
- 在ViewModel中创建一个持有某种数据类型的LiveData ,通常是用子类MutableLiveData定义
- 通过 observe 方法可以订阅修改数据的通知
- 通过 postValue()或者 setValue() 方法发送事件更新数据
- 已经订阅的 Observer 就能够得到数据更改时的通知并回调 onChanged() 方法
- 在onChanged()方法中更新数据更新UI
LiveData简单使用
//观察者角色
myViewModel.getData().observe(this, new Observer<String>() {
@Override
public void onChanged(String data) {
mainBinding.textView.setText(data);
}
});
//被观察者角色
mainBinding.textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
myViewModel.getData().setValue("狗哥很帅`!");`
}
});
源码分析
LiveData中的observe()源码解析
先看看LiveData中observe()方法的参数
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
}
思考
我们看到LiveData源码中observe()方法第一个参数是 LifecycleOwner,而我们代码中传递的是当前页面上下文this,为什么不会报错 ?this 和 LifecycleOwner 有何关系呢 ?
分析
我们看当前 MainActivity继承自 AppCompatActivity
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
再看看AppCompatActivity,
public class AppCompatActivity extends FragmentActivity implements AppCompatCallback,
TaskStackBuilder.SupportParentable, ActionBarDrawerToggle.DelegateProvider {
}
发现AppCompatActivity又继承自FragmentActivity,在继续看看FragmentActivity是什么东西:
public class FragmentActivity extends ComponentActivity implements
ActivityCompat.OnRequestPermissionsResultCallback,
ActivityCompat.RequestPermissionsRequestCodeValidator {
又发现FragmentActivity继承自ComponentActivity,这时候哥哥们可能会有些不耐烦了,稳住稳住,马上就到了:
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
LifecycleOwner,
ViewModelStoreOwner,
HasDefaultViewModelProviderFactory,
SavedStateRegistryOwner,
OnBackPressedDispatcherOwner {}
}
这时候大家发现了,MainActivity 的终极父类其实是实现了 LifecycleOwner 的接口,所以传递this不会报错。而observe()的第一个参数其实就相当于一个被观察者,第二个参数observer就相当于观察者。
分析完observe()的构造方法,接下来我们看看observe()方法做了哪些操作:
@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);
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;
}
owner.getLifecycle().addObserver(wrapper);
}
1. assertMainThread("observe");
assertMainThread("observe");
static void assertMainThread(String methodName) {
if (!ArchTaskExecutor.getInstance().isMainThread()) {
throw new IllegalStateException("Cannot invoke " + methodName + " on a background"
+ " thread");
}
}
我们可以查看他的源码发现: 这个个方法中判断了当前线程是否为主线程,如果不是主线程则抛出异常
2. if()判断生命周期状态
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
return;
}
通过owner获取到当前页面的生命周期状态是否被销毁,如果销毁则return,可以避免内存泄漏的情况
3. LifecycleBoundObserver装饰器
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
相当于一个装饰器,将持有者(被观察者Activity)和观察者都装进去
LifecycleBoundObserver源码
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
//如果前页面的生命周期状态是否被销毁,如果销毁则removeObserver(mObserver),即移除Observer;
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
4. ObserverWrapper缓存
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
mObservers源码
private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
new SafeIterableMap<>();
mObservers是一个Map,相当于缓存,缓存一份装饰器,key为observer,value为装饰器wrapper
总结
整个LiveData都是时刻去观察生命周期的状态,从而从根源上避免了内存泄漏的出现,这也是目前好多公司采用jetpack的原因
LiveData中setValue()源码解析
这里我还是重复放一下使用的那段代码吧,也便于大佬们更好的分析,大佬们莫怪!
//观察者角色
myViewModel.getData().observe(this, new Observer<String>() {
@Override
public void onChanged(String data) {
mainBinding.textView.setText(data);
}
});
//被观察者角色
mainBinding.textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
myViewModel.getData().setValue("哈哈哈哈");
}
});
思考
观察者是如何监听到被观察者的数据实时变化呢?
分析
我们来看被观察者的触发过程:
myViewModel.getData().setValue("哈哈哈哈");
这里发现其实是通过setValue()方法进行触发的,那我们进去看看这个setValue()方法:
@SuppressWarnings("WeakerAccess")
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);
}
}
通过super.setValue(value),调用父类的setValue(),将 value 传入,即 LiveData 的setValue(value)方法。 我们继续看看 super.setValue(value)方法:
@MainThread
protected void setValue(T value) {
//这里又一次判断了是否为主线程,如果不是主线程,则抛出异常
assertMainThread("setValue");
mVersion++;
//将value赋值给data
mData = value;
//分发value,
dispatchingValue(null);
}
mVersion
LiveData内维护的mVersion表示的是发送信息的版本,每次发送一次信息, 它都会+1, 而ObserverWrapper内维护的mLastVersion为订阅触发的版本号, 当订阅动作生效的时候, 它的版本号会和发送信息的版本号同步.他们初始值都为-1。
思考
dispatchingValue(null) 参数传递 null 有何意义呢 ?
分析
我们继续查看dispatchingValue()的源码
@SuppressWarnings("WeakerAccess") /* synthetic access */
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
这里我们主要分析这段代码:
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
当我们有多个被观察者时,遍历所有的观察者并取出观察者:即:
new Observer<String>() {
@Override
public void onChanged(String data) {
mainBinding.textView.setText(data);
}
}
然后通过considerNotify唤醒
considerNotify()
@SuppressWarnings("unchecked")
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
if (!observer.mActive) {
return;
}
这个判断什么意思呢?
如果 observer.mActive ==true , 则我们的当前页面时可见状态,即处于 onResume() 状态,而这里是 !observer.mActive,即当前页面处于不可见的状态,而后 return ;
这样做的好处是又一次的去避免了内存的泄漏;
举个例子
举个栗子:假如我们刚启动Activity,然后迅速的关闭掉Activity,这时候刚打开这个Activity的时候已经发起了网络请求,进而要去请求数据并通知界面去刷新UI,这时候就会走considerNotify方法去通知控件,而当页面关闭的话,是找不到控件的,这时候就会引发崩溃问题,所以这里这个判断又一次的判断了当前页面是否处于可见状态,如果为可见状态则去onChanged数据,如果不可见则直接return,也从而避免了崩溃和内存泄漏的问题!
observer.mObserver.onChanged((T) mData);
mData即为改变的数据,通过mObserver调用onChange(mData),这时候数据 data 就回到了 onChanged()方法中了。
//观察者角色
myViewModel.getData().observe(this, new Observer<String>() {
@Override
public void onChanged(String data) {
//数据就回到了这里的onChanged方法
mainBinding.textView.setText(data);
}
});
总结
- LiveData 内部实现了观察者模式,如果数据要同时通知几个界面,可以采取这种方式
- LiveData 数据变化的时候,会回调 Observer 的 onChange 方法,但是回调的前提是 lifecycleOwner(即所依附的 Activity 或者 Fragment) 处于 onStart() 或者 onResume() 状态,它才会回调,否则,必须等到 lifecycleOwner 切换到前台的时候,才回调,其内部解决了因为Lifecycle而导致的崩溃,内存泄漏等问题。因此,这对性能方面确实是一个不小的提升。
传送门
这是我写的一个基于ViewModel + LiveData+ DataBinding、多语言化、矢量图、约束性布局的篮球计分器的一个学习的简单Demo