LiveData的基本使用
创建一个LiveData的类:
kotlin
object MyLiveData { // 单例
// 懒加载
val info1: MutableLiveData<String> by lazy { MutableLiveData() }
}
在Activity中:
kotlin
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val textView : TextView = findViewById(R.id.tv_textview)
// 1 观察者 眼睛 环节
MyLiveData.info1.observe(this, {
textView.text = it // 更新UI
})
```
// 手动考虑释放工作
MyLiveData.value1.observeForever({
})
}
override fun onDestroy() {
super.onDestroy()
// 手动释放
// MyLiveData.value1.removeObserver()
}
}
LiveData存在数据黏性的问题,就是先设置值,后订阅也能收到值,这是因为一般的,我们只关心订阅之后的数据变化。但这种行为在某些情况下是有用的,比如配置更改(如屏幕旋转)后恢复UI状态,但在其他场景中可能导致不希望的重复数据更新。 如何解决这个问题呢?可以通过反射来处理:
js
/**
* 单例模式 去掉黏性事件(有关闭黏性的开关) KT的版本
*/
object OKLiveDataBusKT {
// 存放订阅者
private val bus : MutableMap<String, BusMutableLiveData<Any>> by lazy { HashMap() }
// 暴露一个函数,给外界注册 订阅者关系
@Synchronized
fun <T> with(key: String, type: Class<T>, isStick: Boolean = true) : BusMutableLiveData<T> {
if (!bus.containsKey(key)) {
bus[key] = BusMutableLiveData(isStick)
}
return bus[key] as BusMutableLiveData<T>
}
// Any? 是 Object , * 星投影 KT泛型的? 有点像 Java ?
class BusMutableLiveData<T> private constructor() : MutableLiveData<T>() {
var isStick: Boolean = false
// 次构造
constructor(isStick: Boolean) : this() {
this.isStick = isStick
}
// 我是先执行
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
super.observe(owner, observer) // 这句会执行父类的 // 启用系统的功能 不写就破坏了
if (!isStick) {
hook(observer = observer)
Log.d("derry", "Kotlin版本的 不启用黏性")
} else {
Log.d("derry", "Kotlin版本的 启用黏性")
}
}
private fun hook(observer: Observer<in T>) {
// TODO 1.得到mLastVersion
// 获取到LivData的类中的mObservers对象
val liveDataClass = LiveData::class.java
val mObserversField: Field = liveDataClass.getDeclaredField("mObservers")
// 私有修饰也可以访问
mObserversField.isAccessible = true
// 获取到这个成员变量的对象 Any == Object
val mObserversObject: Any = mObserversField.get(this)
// 得到map对象的class对象 private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
val mObserversClass: Class<*> = mObserversObject.javaClass
// 获取到mObservers对象的get方法 protected Entry<K, V> get(K k) {
val get: Method = mObserversClass.getDeclaredMethod("get", Any::class.java)
// 私有修饰也可以访问
get.isAccessible = true
// 执行get方法
val invokeEntry: Any = get.invoke(mObserversObject, observer)
// 取到entry中的value is "AAA" is String is是判断类型 as是转换类型
var observerWraper: Any? = null
if (invokeEntry != null && invokeEntry is Map.Entry<*, *>) {
observerWraper = invokeEntry.value
}
if (observerWraper == null) {
throw NullPointerException("observerWraper is null")
}
// 得到observerWraperr的类对象
val supperClass: Class<*> = observerWraper.javaClass.superclass
val mLastVersion: Field = supperClass.getDeclaredField("mLastVersion")
mLastVersion.isAccessible = true
// TODO 2.得到mVersion
val mVersion: Field = liveDataClass.getDeclaredField("mVersion")
mVersion.isAccessible = true
// TODO 3.mLastVersion=mVersion
val mVersionValue: Any = mVersion.get(this)
mLastVersion.set(observerWraper, mVersionValue)
}
}
}
使用方式:
js
源码解析
粘性数据的由来
LiveData为为什么能够观察数据的变化,这与他实现LifecycleBoundObserver是分不开的。实现这个接口,让他又能能够感知被观察者生命周期的能力。 在LiveData中有下边这个重要的函数,状态的变化分发都是通过他进行的
scss
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
shouldBeActive判断了当前被观察者(Activity, Fragment)的生命周期至少是STARTED才会继续进行数据的分发
scss
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
dispatchingValue来实现真正的数据分发。
scss
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);
}
}
dispatchingValue进入后
ini
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
// 该值为空的时候,走的是setValue和postValue,不为空的时候,是在状态变化的时候进行的分发
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;
}
considerNotify又进行了状态检测,这是为什么呢?因为页面生命周期变化可能很快,我们要实时的检测他的状态。
kotlin
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;
}
// 决定黏性事件的执行与非执行,如果我们先设置了值,那么这里的mLastVersion会在setvalue的时候执行++,导致这两个值不相等,进而会走分发。去掉粘性也很简单,只需要通过反射让这两个值相等就行了。
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
//noinspection unchecked
observer.mObserver.onChanged((T) mData);
}
setValue与postValue
postValue
ini
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
ini
private final Runnable mPostValueRunnable = new Runnable() {
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
//noinspection unchecked
setValue((T) newValue);
}
};
typescript
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
可见postValue与setValue的区别就是一个线程的切换。因此如果你需要在子线程使用livedata,需要用postValue来实现更新。
再次回调dispatchingValue,这次的initiator事空值,为什么else分支里边是一个循环呢?这是因为对于同一个变量,可能有多个观察者,我们需要通过遍历将所有的值分发给观察者。
ini
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;
}