Google官方解释:
LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。
说白了LiveData可以监听数据改变,从而进行操作。
先看三种场景:
1.通常情况--基本用法
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val textview:TextView = findViewById(R.id.tv)
//写法1:采用lamda表达式
MyLiveData.info.observe(this,{
textview.text = it
})
//写法2:采用常规写法 传LifeCycleOwner 和new一个Observer并重写onChange方法
// MyLiveData.info.observe(this,object: Observer<String>{
// override fun onChanged(t: String?) {
//
// }
// })
MyLiveData.info.value = "vivid-momo 1rd" //主线程使用setValue
//在KT中就等价与setValue
thread{
Thread.sleep(3000)
MyLiveData.info.postValue("vivid-momo 2nd") //异步线程使用postValue
}
thread{
Thread.sleep(6000)
MyLiveData.info.postValue("vivid-momo 3rd") //异步线程使用postValue
}
}
}
//单例类+懒加载
object MyLiveData {
val info:MutableLiveData<String> by lazy { MutableLiveData() }
}
结果:启动后界面中的TextView默认显示"vivid-momo 1rd"后显示2nd最后显示3rd
?2.数据变化界面什么时候刷新
//LiveData UI 更新时机
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
val but:Button = findViewById(R.id.but)
but.setOnClickListener{
startService(Intent(this,MyService::class.java))
Toast.makeText(this, "启动Service", Toast.LENGTH_SHORT).show()
}
MyLiveData.info.observe(this, {
Log.d("vivid-momo", "onCreate: 接受数据....")
Toast.makeText(this, "接受到的数据是: ${it}", Toast.LENGTH_SHORT).show()
})
}
}
object MyLiveData {
val info:MutableLiveData<String> by lazy { MutableLiveData() }
}
class MyService : Service() {
val TAG = "vivid-momo"
override fun onBind(intent: Intent): IBinder ? = null
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
thread {
for (x in 1..10000){
Log.d(TAG, "onStartCommand: 消息发送开始....${x}")
MyLiveData.info.postValue("消息列表 -- ${x}")
Thread.sleep(5000)
}
}
return super.onStartCommand(intent, flags, startId)
}
}
MainActivity: but用于启动Service 并且启动对MyLiveData中info观察
Service:隔5S修改一次数据
结果:
2022-04-25 01:09:14.962 27593-27758/com.example.livedatademo D/vivid-momo: onStartCommand: 消息发送开始....1
2022-04-25 01:09:15.042 27593-27593/com.example.livedatademo D/vivid-momo: onCreate: 接受数据....
2022-04-25 01:09:19.963 27593-27758/com.example.livedatademo D/vivid-momo: onStartCommand: 消息发送开始....2
2022-04-25 01:09:19.964 27593-27593/com.example.livedatademo D/vivid-momo: onCreate: 接受数据....
2022-04-25 01:09:24.964 27593-27758/com.example.livedatademo D/vivid-momo: onStartCommand: 消息发送开始....3
2022-04-25 01:09:24.966 27593-27593/com.example.livedatademo D/vivid-momo: onCreate: 接受数据....
2022-04-25 01:09:29.965 27593-27758/com.example.livedatademo D/vivid-momo: onStartCommand: 消息发送开始....4
2022-04-25 01:09:34.968 27593-27758/com.example.livedatademo D/vivid-momo: onStartCommand: 消息发送开始....5
2022-04-25 01:09:39.970 27593-27758/com.example.livedatademo D/vivid-momo: onStartCommand: 消息发送开始....6
2022-04-25 01:09:41.330 27593-27593/com.example.livedatademo D/vivid-momo: onCreate: 接受数据....
2022-04-25 01:09:44.971 27593-27758/com.example.livedatademo D/vivid-momo: onStartCommand: 消息发送开始....7
2022-04-25 01:09:44.973 27593-27593/com.example.livedatademo D/vivid-momo: onCreate: 接受数据....
2022-04-25 01:09:49.973 27593-27758/com.example.livedatademo D/vivid-momo: onStartCommand: 消息发送开始....8
2022-04-25 01:09:49.975 27593-27593/com.example.livedatademo D/vivid-momo: onCreate: 接受数据....
2022-04-25 01:09:54.974 27593-27758/com.example.livedatademo D/vivid-momo: onStartCommand: 消息发送开始....9
2022-04-25 01:09:54.975 27593-27593/com.example.livedatademo D/vivid-momo: onCreate: 接受数据....
原因:发送数据456是,退出了APK,所以不接受数据,故此UI不刷新
3:特殊情况下LiveData如何处理
先修改数据后启动数据观察
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main3)
val but:Button = findViewById(R.id.but)
but.setOnClickListener {
MyLiveData.info.value ="vivid-momo 先改变数据"
startActivity(Intent(this,StartObserver::class.java))
}
}
}
object MyLiveData {
val info:MutableLiveData<String> by lazy { MutableLiveData() }
}
class StartObserver : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main4)
MyLiveData.info.observe(this, {
Log.d("vivid-momo", "onCreate: 接受到的数据是:${it}")
Toast.makeText(this, "接受到的数据是:${it} ", Toast.LENGTH_SHORT).show()
})
}
}
结果:
2022-04-25 01:14:00.172 28144-28144/com.example.livedatademo D/vivid-momo: onCreate: 接受到的数据是:vivid-momo 先改变数据
先修改了数据在启动观察,仍然接受到了启动观察前的数据!!!
问题1:setValue和postValue到底有什么区别?
问题2:LiveData刷新数据有什么限制?
问题3:为什么先修改数据后启动监听,仍可以接受到启动监听前的数据?
回答这三个问题之前,我们先看看MyLiveData.info.observe(this,{ })中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);//结合LifeCycle
}
第一个参数:this 指当前MainActivity的环境变量,由于MainActivity继承了ComponentActivity,而ComponentActivity实现了LifecycleOwner 所以this 中就存在了LifecycleOwner。
第二个参数:new了一个Observer
observe中将this和Observer通过LifecycleBoundObserver重新实例化成wrapper?
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
LifecycleBoundObserver实例的时候会把MainActivity的环境(this)传给父类ObserverWrapper
this(LifecycleOwner)传给ObserverWrapper 能干什么?下面两个是关键方法
@Override
boolean shouldBeActive() {
//通过拿到的LifecycleOwner判断当前的MainActivity是否是活动状态
//STARTED/RESUMED
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
//如果MainActivity是STARTED/RESUMED状态执行
activeStateChanged(shouldBeActive());
}
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);//newActive 为true执行
}
}
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) { //initiator 为true,不为空
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;
}
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
// Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
//
// we still first check observer.active to keep it as the entrance for events. So even if
// the observer moved to an active state, if we've not received that event, we better not
// notify for a more predictable notification order.
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
//noinspection unchecked
observer.mObserver.onChanged((T) mData); //回调执行onChanage方法
}
mDate是什么东西?
此时我们就要回答 问题1:setValue和postValue到底有什么区别?
//LiveData.java
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
当你执行setValue的时候,把你要设置的数据赋值给了mDate,所以onChanage方法中就可以获取到你设置的值(其实就是"vivid-momo 1rd"字符串)。
再看postValue是如何执行?
//LiveData.java
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
//执行子主线程切换
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
private final Runnable mPostValueRunnable = new Runnable() {
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
//noinspection unchecked
setValue((T) newValue);
}
};
postVlaue中将我们要改变得字符串赋值给了mPendingData ,而在mPostValueRunnable 中又将mPendingData赋值给了newValue。
但是mPostValueRunnable中还是用setValue去设置数据的,而setValue执行用于主线程,所以说一定使用了子线程切换为主线程执行。
子线程切换为主线程
//DefaultTaskExecutor.java
@Override
public void postToMainThread(Runnable runnable) {
if (mMainHandler == null) {
synchronized (mLock) {
if (mMainHandler == null) {
mMainHandler = new Handler(Looper.getMainLooper());
}
}
}
//noinspection ConstantConditions
mMainHandler.post(runnable);
}
问题2:LiveData刷新数据有什么限制?
通过上面ObserverWrapper中的activeStateChanged方法分析只有但MainActivity处于STARTED/RESUMED状态数据才会被分发,这也就解释了为什么当我们退出apk是接受不到MyService.java 中 postValue修改的值。
问题3:为什么先修改数据后启动监听,仍可以接受到启动监听前的数据?
先修改数据,后启动监听,此时监听可以收到之前修改的数据此时收到的数据成为粘性数据。
为什么后启动监听能收到之前的数据?如果需要去掉粘性如何操作?
一切的一切还要下面这段代码开始解释:
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);
}
收到了数据那就说明observer.mObserver.onChanged((T) mData);肯定是执行了的
也就是说前面的三个判断没有命中执行return
第一个:当我们通过点击事件跳转到启动StartObserver.java中,之前在activeStateChanged方法中mActive赋值只有当观察者处于STARTED/RESUMED状态mActive为true,否则为false,当我们第一次进入StartObserver.java中此时mActive为true所以第一个判断不命中
第二个:当观察者(StartObserver.java)处于非活动状态,需要通过activeStateChanged更新mActive的值,当StartObserver.java可见时第二个判断也不会命中
第三个:当观察者(StartObserver.java)第一次启动的时候mVersion 的值为-1;
但是当执行setValue的时候对mVersion 进行了累加操作,此时mVersion 值为0;
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++; //执行的累加
mData = value;
dispatchingValue(null);
}
public abstract class LiveData<T> {
static final int START_VERSION = -1;
......
private int mVersion = START_VERSION;
......
}
private abstract class ObserverWrapper {
final Observer<? super T> mObserver;
boolean mActive;
int mLastVersion = START_VERSION;
......
}
而mLastVersion 初始值为-1;所以第三个判断也不会命中,所以数据会分发下去,但是如果我们先不执行setValue/postValue,mVersion就会和mLastVersion相等都为-1,就不会分发数据,也就是说如果我们不想要之前设置的数据,可以通过第三个判断来去除。
具体方法:设置数据后通过反射重新给mVersion赋值为-1.此时再去启动监听就不会收到之前设置的数据,也就是去除了粘性数据。
特别注意:
在不去除粘性的情况下,在启动观察前多次修改数据,只有最后一次的数据会被观察者接收到。
也就是说StartObserver中执行接收到"vivid-momo ?先改变数据4"这一条数据
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main3)
val but:Button = findViewById(R.id.but)
but.setOnClickListener {
MyLiveData.info.value ="vivid-momo 先改变数据0"
MyLiveData.info.value ="vivid-momo 先改变数据1"
MyLiveData.info.value ="vivid-momo 先改变数据2"
MyLiveData.info.value ="vivid-momo 先改变数据3"
MyLiveData.info.value ="vivid-momo 先改变数据4"
startActivity(Intent(this,StartObserver::class.java))
}
}
}
总结:LiveData是结合LifeCycle的五个状态实现对数据的有效监听和刷新。
|