1.LiveData
LiveData是Android Jetpack包提供的一种可观察的数据存储器类,它可以通过添加观察者被其他组件观察其变更。不同于普通的观察者,LiveData最重要的特征是它具有生命周期感知能力,它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保LiveData仅更新处于活跃生命周期状态的应用组件观察者。如在Activity中如果数据更新了但Activity已经处于destroy状态,则LiveData就不会通知Activity(observer)了。此外,LiveData还有许多优点,比如不会完成内存泄露等。
LiveData有两个子类:MutableLiveData和MediatorLiveData。MutableLiveData针对单个需要观察的数据进行了封装,而MediatorLiveData则可以观察其它的LiveData。开发过程中通常使用LiveData的子类,而不是去继承LiveData。
LiveData通常会配合ViewModel一起使用,ViewModel负责触发数据的更新,更新会通知单LiveData,然后LiveData再通知活跃状态的观察者。当然,LiveData也可以单独使用。
比如MutableLiveData的使用方法:
private void liveDataTest(){
MutableLiveData<String> mutableLiveData = new MutableLiveData<>();
mutableLiveData.observe(this, new Observer<Integer>() {
@Override
public void onChanged(Integer integer) {
//如果数据有变化的话,这里会接收到通知,可以在这里可以做一些反应,比如更新界面
}
});
mutableLiveData.setValue("我的值变化了");
}
分为三步:
①创建对应数据类型的LiveData
②添加观察者与Lifecycle建立联系
③发送对应的数据进行更新
2.LiveData使用
①首先引入依赖
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
②布局文件activity_live_data_test.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".LiveDataTestActivity">
<TextView
android:id="@+id/tv_text"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="100dp"
android:gravity="center"
android:textSize="30sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="200dp"
android:gravity="center"
android:orientation="horizontal">
<ImageButton
android:id="@+id/img_button_add"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_marginRight="20dp"
app:srcCompat="@drawable/up_24"
/>
<ImageButton
android:id="@+id/img_button_subtract"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_marginLeft="20dp"
app:srcCompat="@drawable/down_24"
/>
</LinearLayout>
</LinearLayout>
③创建ViewModelWithLiveData类继承于ViewModel,在这个类里面声明变量
public class ViewModelWithLiveData extends ViewModel {
private MutableLiveData<Integer> LikedNumber;
public MutableLiveData<Integer> getLikedNumber() {
if (LikedNumber == null) {
//LikedNumber是对象类型,不是基本数据类型,所以要保证变量不是空的
LikedNumber = new MutableLiveData<>();
LikedNumber.setValue(0); //初始化为0
}
return LikedNumber;
}
public void addLikedNumber(int n) {
LikedNumber.setValue( LikedNumber.getValue() + n);
}
}
④给viewModelWithLiveData里面的变量添加一个观察,点击按钮实现+1、-1操作
public class LiveDataTestActivity extends AppCompatActivity {
private ViewModelWithLiveData viewModelWithLiveData;
private TextView tv_text;
private ImageButton img_button_add;
private ImageButton img_button_subtract;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView( R.layout.activity_live);
tv_text = findViewById(R.id.tv_text);
img_button_add = findViewById(R.id.img_button_add);
img_button_subtract = findViewById(R.id.img_button_subtract);
viewModelWithLiveData = new ViewModelProvider(this).get(ViewModelWithLiveData.class);
//给viewModelWithLiveData里面的变量添加一个观察,观察它自己,如果数据发生变化则呼叫下面的函数
//observe()的第一个参数:需要具有LifeCycle管理功能的一些对象。Activity就是具有管理LifeCycle功能的对象,系统已经帮我们做好了,不用在其他地方取消观察,只需要添加观察就可以了
viewModelWithLiveData.getLikedNumb er().observe(this, new Observer<Integer>() {
@Override
public void onChanged(Integer integer) { //当数据发生改变的时候 呼叫这个函数
tv_text.setText( String.valueOf(integer));
}
});
img_button_add.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
viewModelWithLiveData.addLikedN umber(1);
}
});
img_button_subtract.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View view) {
viewModelWithLiveData.addLikedN umber(-1);
}
});
}
}
并且,旋转屏幕,切换系统语言等配置时,数据不会丢失。
LiveData的好处:
①监听与其绑定的界面的生命周期。因此,使用LiveData就不需要手动管理它的生命周期了。
②组件能及时响应LiveData的数据变化,组件总能拿到LiveData的最新数据。当然,被绑定的组件响应LiveData是有一定的前提的,那就是LiveData数据发生变化,且组件处于活跃状态。也就是说,LiveData数据即使发生了变化,也不一定会响应onChanged函数,因为它必须要求LiveData数据所在的界面处于活跃状态,才会响应onChanged函数。
③生命周期自动解绑,它能够在组件销毁的时候自动解绑,大大降低了应用产生内存泄露的概率。
LiveData确实能解决内存泄漏问题,但是如果使用不当,其实还是会出现内存泄漏的。例如,有一个Activity,Activity包含了一个Fragment,Fragment中有一个LiveData,因此Fragment引用了LiveData。然后LiveData通过observe方法把Activity当作owner进行了绑定,那么这时候,LiveData的生命周期将和Activity一样。如果这时候因为某种原因,Fragment被销毁了,那么LiveData将不会被销毁,因为它被Activity引用着。LiveData本该回收却无法被回收,那么LiveData就发生内存泄漏了。
3.LiveData源码
①observe方法
LiveData使用observe()方法监听与其绑定的界面的生命周期。
LiveData.java:
@MainThread
public void observe(LifecycleOwner owner, Observer<? super T> observer) {
assertMainThread("observe"); //只能在主线程调用这个方法
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
return; //如果owner的生命周期已经是DESTROYED状态,则不再往下执行
}
//将外部传进的observer对象封装成一个LifecycleBoundObserver对象
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
//将observer和wrapper存放到map中
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException( "Cannot add the same observer with different lifecycles"); //同一个观察者不能观察不同的LifecycleOwner
}
if (existing != null) {
return;
}
owner.getLifecycle().addObserver(wrapper);
}
首先,将外部传进的observer对象封装成LifecycleBoundObserver对象,对象名称为wrapper,其实LifecycleBoundObserver就是一个可以监听生命周期的类,可以看看LifecycleBoundObserver类的构造方法:
LiveData.LifecycleBoundObserver.java:
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
final LifecycleOwner mOwner;
LifecycleBoundObserver(LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
// …………………………
}
public interface GenericLifecycleObserver extends LifecycleEventObserver { }
public interface LifecycleEventObserver extends LifecycleObserver {
void onStateChanged(LifecycleOwner source, Lifecycle.Event event);
}
可以看到,LifecycleBoundObserver实现了GenericLifecycleObserver这个接口,而实际上这个接口最终继承自LifecycleObserver
接口,LifecycleObserver
就是使用lifecycle
的时候调用addObserver时需要传递的参数。
所以,通过new LifecycleBoundObserver( owner, observer)方法得到的wrapper实际上就是一个LifecycleObserver。
在LifecycleBoundObserver类构造方法中,将observer传给其父类使用,而其父类是ObserverWrapper,看看ObserverWrapper
的构造方法:
LiveData.ObserverWrapper.java:
private abstract class ObserverWrapper {
final Observer<? super T> mObserver;
boolean mActive;
int mLastVersion = START_VERSION;
ObserverWrapper(Observer<? super T> observer) {
mObserver = observer;
}
// ………………………………
}
可以看到,实际上只是把observer赋值给ObserverWrapper类的mObserver成员变量罢了。
继续回到LiveData的observe方法:
LiveData.java:
private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers = new SafeIterableMap<>();
@MainThread
public void observe(LifecycleOwner owner, Observer<? super T> observer) {
assertMainThread("observe");
//如果owner的生命周期为DESTROYED,直接return
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
return;
}
//将外部传进的observer对象封装成一个LifecycleBoundObserver对象
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
//将observer和wrapper存放到mObservers中
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);
}
mObservers.putIfAbsent(observer, wrapper)这行代码,将observer作为键,wrapper作为值存放到mObservers中,并且会返回一个ObserverWrapper对象。
mObservers是一个由链表实现的支持键值对存储的数据结构,同时,它支持在遍历的过程中删除任意元素,我们可以暂且把它理解为保存observer对象的集合。
如果ObserverWrapper不为null,则observe这个方法会直接return。ObserverWrapper在什么情况不为null呢?
如果观察者observer已经在mObservers这个列表中,并且observer已经有另一个所有者owner,就会不为null。
这是为了防止同一个observer被多个LifecycleOwner绑定,即一个LiveData中的同一个observer只能跟一个LifecycleOwner绑定。否则会抛出“Cannot add the same observer with different lifecycles”的异常。
在observe方法的最后,调用了owner.getLifecycle().addObserver(wrapper)方法,使得wrapper和owner的生命周期进行了绑定。也就是说,observer此时就可以监听到owner对应的界面的生命周期的变化了。
②setValue方法
setValue方法是用来更新LiveData数据的。
LiveData.java:
@MainThread
protected void setValue(T value) {
assertMainThread("setValue"); //setValue方法要求在主线程调用,在其他线程使用postValue
mVersion++; 辅助做数据是否有更新的判断
mData = value;
dispatchingValue(null);
}
首先,setValue方法有个@MainThread注解,说明这个方法只能在主线程中使用,然后在setValue中,将value赋值给mData变量,同时mVersion变量加1,mVersion就是数据的版本,它是用来标记数据是否变化的。
方法最后调用了dispatchingValue(null)方法实现数据分发,进入该方法:
LiveData.java:
void dispatchingValue(ObserverWrapper initiator) {
//如果当前正在做数据分发,则不做重复处理
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true; //标记事件分发状态为true
do {
mDispatchInvalidated = false;
if (initiator != null) {
//observe方法被调用时,从这里触发分发
considerNotify(initiator);
initiator = null;
} else {
//setValue触发遍历观察该LiveData的所有观察者,分发setValue事件
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator = mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify( iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
可以看到,dispatchingValue方法中有个while循环,在while循环里面,由于initiator为null,所有走else分支的代码,这里又有个for循环,这个for循环是用来遍历mObservers中的observer对象的,然后通过considerNotify方法将遍历到的observer对象进行处理。
看看considerNotify方法,该方法针对每个观察者做处理,判断是否需要分发和完成分发事件:
LiveData.java:
private void considerNotify(ObserverWrapper observer) {
//如果观察者不活跃就放弃分发,观察者活跃的逻辑是处于STARTED和RESUMED之间
if (!observer.mActive) {
return;
}
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
//如果该观察者已经接受过数据了,也不再进行分发
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion; //对观察者进行分发版本记录
observer.mObserver.onChanged((T) mData); //调用观察者的onChanged事件完成分发
}
首先做了一个判断,外部传入的observer对象是否处于活跃状态,不处于活跃状态则直接return这个方法。从这里就可看出,即使数据更新了,但如果界面不处于活跃状态,也不会对数据更新做响应。
然后是mVersion这个变量以及mLastVersion变量,判断observer.mLastVersion变量如果小于mVersion,会把mVersion的值赋值给observer.mLastVersion变量,这种情况就说明数据是新的数据,就可以执行observer的onChanged方法把mData回调出去了。
③postValue方法
LiveData.java:
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMai nThread(mPostValueRunnable);
}
postValue方法中,外部传进来的value会赋值给mPendingData,方法的最后会调用postToMainThread方法,postToMainThread,看这个方法的命名应该也能看出来一些东西,就是将这个runnable发布到主线程处理,进入postToMainThread详细看看:
ArchTaskExecutor.java:
@Override
public void postToMainThread(Runnable runnable) {
mDelegate.postToMainThread(runnable);
}
它通过调用mDelegate的postToMainThread方法,mDelegate实际上就是DefaultTaskExecutor这个类,那么再进入这个类的postToMainThread看看:
DefaultTaskExecutor.java:
@Override
public void postToMainThread(Runnable runnable) {
if (mMainHandler == null) {
synchronized (mLock) {
if (mMainHandler == null) {
mMainHandler = new Handler(Looper.getMainLooper());
}
}
}
mMainHandler.post(runnable);
}
在这个方法中,先判断mMainHandler对象是否为null,如果为null,就创建一个,注意,它是通过Looper.getMainLooper()参数来创建的,说明这个这个mMainHandler就是主线程的handler对象。
最后调用mMainHandler.post(runnable)方法,将runnable对象交给主线程的handler来处理。
那么runnable执行了什么东西呢?
回到postValue方法,发现runnable就是mPostValueRunnable,看mPostValueRunnable是怎么定义的:
LiveData.java:
private final Runnable mPostValueRunnable = new Runnable() {
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
setValue((T) newValue);
}
};
看到它的run方法,先定义了个newValue变量,然后加锁对newValue赋值为mPendingData变量,mPendingData是在postValue方法内第三行赋值的,前面已经看到过了,然后将mPendingData置为NOT_SET。最后调用setValue方法。
所以,postValue方法实际上就是将线程切到主线程去处理setValue方法。