livedata是jetpack中的框架,可用于activity等监听数据的变化。前题是他们要实现LifecycleOwner。
是用来观察带有生命周期对象的利器,如:继承于SupportActivity的activity。。
用法案例(伪代码)
两步:
1.创建Observer对象,用于刷新ui。
2.调用livedata的observe方法。
1) // Create the observer which updates the UI.
final Observer<String> nameObserver = new Observer<String>() {
@Override
public void onChanged(@Nullable final String newName) {
// Update the UI, in this case, a TextView.
nameTextView.setText(newName);
}
};
2)//这里的this,一般是SupportActivity的子类。
livedata.observe(this, nameObserver);
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
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);
}
observe方法流程:
1.LifecycleOwner的getLifecycle()的当前状态,即不能是DESTROYED。否则立即返回,什么都不执行。这里的getLifecycle(),在SupportActivity中是LifecycleRegistry。后面分析。
2.将observer和LifecycleOwner一起封装到LifecycleBoundObserver类
3.将observer本身和封装好的LifecycleBoundObserver放入livedata的成员变量mObservers中(因为livedata被观察的数据可以有多个)
4.判断如果是相同的observer被添加到不同的lifecycles,则抛IllegalArgumentException
5.如果mObservers中已经存在相同observer,则返回不重复添加。 后面分析ObserverWrapper的数据结构,以及putIfAbsent方法。
6.lifecycle开始观察LifecycleBoundObserver。
========================== 注册好观察者对象之后,接着看被观察者livedata数据更新的方法
更新数据的方法:
1.setvalue
2.postvalue://通过主线程的handler将setvalue任务发送到messagequeue。
猜测下面代码的执行顺序
* liveData.postValue("a");
* liveData.setValue("b");
结果:先执行b,后执行a
原理:同handler发送消息机制
postvalue执行流程:
1.判断等待执行的数据是否已设置。
a)若等待执行的数据为(NOT_SET)状态,则添加任务到主线程messagequeue。
b)若已有设置数据等待执行,则返回
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);//就是用主线程的handler发送任务到messagequeue
}
// postvalue的runnable任务
private final Runnable mPostValueRunnable = new Runnable() {
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
//noinspection unchecked
setValue((T) newValue);
}
};
2.分析代码:
设计思想: 线程安全
思考:为什么postValue和mPostValueRunnable都会需要synchronized代码块?要知道postValue支持异步,但mPostValueRunnable永远是在主线程中执行。为什么还要给他加锁
private final Object mDataLock = new Object();
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
答案: mPostValueRunnable只会在主线程中执行。因为他的handler是发送到主线程的messagequeue中。假如这时子线程发送更新数据的任务,如果不等待主线程的mPendingData传值给newValue,并且将自己设置为(NOT_SET)这两步都执行完成,postValue中的mPendingData将可能不是NOT_SET,导致异步数据添加失败。具体答案,请看后面的内容:查缺补漏。
衍生出的新问题: 主线程在执行任务,或者异步添加任务会导致相互等待锁,导致线程阻塞,不过由于涉及mPendingData相关的代码量少(都两行),执行速度快。所以性能方面也不会太受影响,但是还是存在数据更新延迟的问题。
需要注意的点:observe,removeObserver,setValue方法,都必须是在主线程。如下源码:
@MainThread
protected void setValue(T value) {}
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {}
@MainThread
removeObserver
查漏补缺:
问题:假设我一个Test类有两个方法,set,get,如果里面都用了synchronized代码块,且锁对象是同一个mDataLock.
当一个线程执行set中的synchronized代码块,如果代码块未执行完,其他持有相同锁的get方法,get中synchronized代码块里的代码能够执行吗?
答案:get不能执行。
测试代码:
package com.example.resthal;
public class Test {
private static final Object mDataLock=new Object();
public static void main(String[] args) {
Test test=new Test();
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
test.set();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
test.get();
}
}).start();
}
}
void set(){
System.out.println("start set"+Thread.currentThread().toString());
synchronized (mDataLock) {
try {
System.out.println("####set mDataLock start####"+Thread.currentThread().toString());
Thread.sleep(2000);
System.out.println("####set mDataLock end####"+Thread.currentThread().toString());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("end set"+Thread.currentThread().toString());
}
void get(){
System.out.println("start get:"+Thread.currentThread().toString());
synchronized (mDataLock) {
System.out.println("***get mDataLock start***"+Thread.currentThread().toString());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("***get mDataLock end***"+Thread.currentThread().toString());
}
System.out.println("end get:"+Thread.currentThread().toString());
}
}
控制台结果:
start setThread[Thread-0,5,main]
####set mDataLock start####Thread[Thread-0,5,main]
start get:Thread[Thread-1,5,main]
start setThread[Thread-2,5,main]
start get:Thread[Thread-3,5,main]
start setThread[Thread-4,5,main]
start get:Thread[Thread-5,5,main]
start setThread[Thread-6,5,main]
start get:Thread[Thread-7,5,main]
start setThread[Thread-8,5,main]
start get:Thread[Thread-9,5,main]
####set mDataLock end####Thread[Thread-0,5,main]
end setThread[Thread-0,5,main]
***get mDataLock start***Thread[Thread-9,5,main]
***get mDataLock end***Thread[Thread-9,5,main]
end get:Thread[Thread-9,5,main]
####set mDataLock start####Thread[Thread-8,5,main]
####set mDataLock end####Thread[Thread-8,5,main]
end setThread[Thread-8,5,main]
***get mDataLock start***Thread[Thread-7,5,main]
***get mDataLock end***Thread[Thread-7,5,main]
end get:Thread[Thread-7,5,main]
####set mDataLock start####Thread[Thread-6,5,main]
####set mDataLock end####Thread[Thread-6,5,main]
end setThread[Thread-6,5,main]
***get mDataLock start***Thread[Thread-5,5,main]
***get mDataLock end***Thread[Thread-5,5,main]
end get:Thread[Thread-5,5,main]
####set mDataLock start####Thread[Thread-4,5,main]
####set mDataLock end####Thread[Thread-4,5,main]
end setThread[Thread-4,5,main]
***get mDataLock start***Thread[Thread-3,5,main]
***get mDataLock end***Thread[Thread-3,5,main]
end get:Thread[Thread-3,5,main]
####set mDataLock start####Thread[Thread-2,5,main]
####set mDataLock end####Thread[Thread-2,5,main]
end setThread[Thread-2,5,main]
***get mDataLock start***Thread[Thread-1,5,main]
***get mDataLock end***Thread[Thread-1,5,main]
end get:Thread[Thread-1,5,main]
总结
可以看到:set mDataLock start和set mDataLock end, get mDataLock start和get mDataLock end,中间不会有其他线程的 同步代码块代码内容 执行。