Jetpack-LiveData

概述

LiveData是一个可以在给定生命周期内观察到的数据持有者类。一个观察者可以与一个LifecycleOwner成对地添加,并且只有当配对的LifecycleOwner处于活动状态时,这个观察者才会收到数据变动的通知。

使用

//使用方式很简单,最核心的两点就是注册,发送和接收,可以理解为带生命周期监听的EventBus

//注册  owner表示具有生命周期的Activity或者Fragment,observer是一个接口,用来处理回传的数据
LiveData.observe(LifecycleOwner owner,Observer observer)
  
//发送 两者的差别很简单,postValue会先切换到主线程,然后再调用setValue
LiveData.postValue(T value)
LiveData.setValue(T value)

开始分析之前的知识点补充

jetpack组件中对生命周期的监听,主要用到了Lifecycle这个类.

这个类型有个枚举类Event ,

//各个属性都对应Activity下的各种生命周期
public enum Event {
  ON_CREATE,
  ON_START,
  ON_RESUME,
  ON_PAUSE,
  ON_STOP,
  ON_DESTROY,
  ON_ANY
}

原理解析

1.从LiveData.observe()开始
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
  assertMainThread("observe");
  if (owner.getLifecycle().getCurrentState() == DESTROYED) {
    //1.生命周期销毁,无法注册
    return;
  }
  //2.LifecycleBoundObserver是一个包装类,对owner和observer进行了一次包装,用于监听
  //  生命周期的变化,以及生命周期变化之后对observer的处理
  LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
  ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
  //TAG-1
  if (existing != null && !existing.isAttachedTo(owner)) {
    throw new IllegalArgumentException("Cannot add the same observer"
                                       + " with different lifecycles");
  }
  if (existing != null) {
    return;
  }
  //3.进行注册
  owner.getLifecycle().addObserver(wrapper);
}

标记处 TAG-1处会抛出一个异常,出现这个异常的原因通常是同一个observer关联了不同的LifecycleOwner导致的。

网上也有人说在使用 Lambda表达式中未使用非静态方法或引用 会出现这个问题,个人测试了下并不会出现这样的问题,因为在 existing.isAttachedTo(owner)中会判断,owner是否是相同的。

如果在ActivityFragment中使用了声明成单例的 LiveData是有可能出现这种错误的。

2.注册成功之后,来看虚假的信息发送者 postValue()
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() {
  @SuppressWarnings("unchecked")
  @Override
  public void run() {
    Object newValue;
    synchronized (mDataLock) {
      newValue = mPendingData;
      mPendingData = NOT_SET;
    }
    setValue((T) newValue);
  }
};

1.postValue是异步线程操作,所以需要加上线程锁
2.mPendingData作为一个临时变量,用来存放post过来的value,同时起到减少锁范围内代码量的作用?
3.postValue最后还是执行到 setValue函数,所以最终的消息发送还是看setValue
  
这里有一个疑问
  
//这代代码为什么不这么写呢?如果有知道的问题能解答一下就好了。
protected void postValue(T value) {
  boolean postTask;
  synchronized (mDataLock) {
    postTask = mPendingData == NOT_SET;
    mPendingData = value;
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
  }
}
3.来看真实的信息发送者 setValue()
@MainThread
protected void setValue(T value) {
    assertMainThread("setValue");
    mVersion++;
    //临时变量,用来保存value
    mData = value;
    dispatchingValue(null);
}

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, ObserverWrapper>> iterator =
           mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
        considerNotify(iterator.next().getValue());
        if (mDispatchInvalidated) {
          break;
        }
      }
    }
  } while (mDispatchInvalidated);
  mDispatchingValue = false;
}

1.dispatchingValue(null) 这里参数为null,表示需要遍历map,给对应的Observer发送消息
2.最终触发点在considerNotify()函数
4.看具体的considerNotify()函数
private void considerNotify(ObserverWrapper observer) {
    //如果观察者当前处于不活跃状态,则不做信息分发,有两种情况观察者处于不活跃状态
    //1.observer被remove掉,
    //2.observer的生命周期在STARTED及之后,对应Activity的生命周期,onStart之后,onStop之前
    if (!observer.mActive) {
        return;
    }
    //在这里会对observer的生命周期进行一次检查
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;
  
    //最后消息从这里发出
    observer.mObserver.onChanged((T) mData);
}

LiveData存在的一些问题

数据倒灌,即先发送事件,再注册也能收得到数据

既然是注册之后,还能收到数据,这说明在注册的过程中触发到了onChanged()函数

1.我们再回到LiveData.observe()
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
    ...
  //这次只需要看这一步就可以了,具体的实现位置在LifecycleRegistry的addObserver函数
  owner.getLifecycle().addObserver(wrapper);
}

//LifecycleRegistry.addObserver()
//看源代码的时候,跟着传入的参数看代码主结构,能快速的了解逻辑
@Override
public void addObserver(@NonNull LifecycleObserver observer) {
  State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
  ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
  ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
    
  //避免重复注册监听
  if (previous != null) {
    return;
  }
    ...
  while ((statefulObserver.mState.compareTo(targetState) < 0
          && mObserverMap.contains(observer))) {
    pushParentState(statefulObserver.mState);
    statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
    popParentState();
    targetState = calculateTargetState(observer);
  }
  ...
}

1.根据observer创建了一个跟生命周期绑定的statefulObserver
2.通过statefulObserver.dispatchEvent()将生命周期事件发送出去。
2.进入ObserverWithState
static class ObserverWithState {
  State mState;
  LifecycleEventObserver mLifecycleObserver;

  ObserverWithState(LifecycleObserver observer, State initialState) {
    //通过Lifecycling创建一个LifecycleObserver,具体的实现类为LifecycleBoundObserver,
    mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
    mState = initialState;
  }
    
  void dispatchEvent(LifecycleOwner owner, Event event) {
    State newState = getStateAfter(event);
    mState = min(mState, newState);
    //这一段是当生命周期状态变化时触发的,具体的处理类为LifecycleBoundObserver
    mLifecycleObserver.onStateChanged(owner, event);
    mState = newState;
  }
}
3.进入LifecycleBoundObserver.onStateChanged()
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
                           @NonNull Lifecycle.Event event) {
  //如果页面销毁,则remove监听者,这也是为什么不需要手动回收监听者的原因
  if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
    removeObserver(mObserver);
    return;
  }
  
  //如果界面处于活跃状态,onStart,onResmue,onPasue 这几个状态都属于活跃状态
  activeStateChanged(shouldBeActive());
}

void activeStateChanged(boolean newActive) {
  //状态相同,则不做处理
  if (newActive == mActive) {
    return;
  }
    ...
  //活跃状态下进行value分发
  if (mActive) {
    dispatchingValue(this);
  }
}
4.最后还是回到了LiveData.dispatchingValue()
void dispatchingValue(@Nullable ObserverWrapper initiator) {
  if (mDispatchingValue) {
    mDispatchInvalidated = true;
    return;
  }
  mDispatchingValue = true;
  do {
    mDispatchInvalidated = false;
    //只不过这一次是进入到这个case中,来对事件进行发送的
    if (initiator != null) {
      considerNotify(initiator);
      initiator = null;
    } else {
      for (Iterator, ObserverWrapper>> iterator =
           mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
        considerNotify(iterator.next().getValue());
        if (mDispatchInvalidated) {
          break;
        }
      }
    }
  } while (mDispatchInvalidated);
  mDispatchingValue = false;
}
5.LiveData的considerNotify()
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);
}

1.mLastVersion是ObserverWrapper的一个version,默认值为-1,每次new ObserverWrapper都会重置
2.mVersion是LiveData的version,默认也为1,每次setValue的时候会+1

如果一个LiveData,先setValue导致mVersion+1,之后在注册监听,就会出现
observer.mLastVersion==-1,mVersion==1的情况,使得数据倒灌。
看到这里产生一个疑问
//这个判断是起到什么作用的呢?为了拦截多线程操作时候产生的信息多次发生的问题吗?
if (observer.mLastVersion >= mVersion) {
  return;
}

数据倒灌的解决方案

第一种方案,自定义LiveData,增加粘性事件的处理逻辑

class BaseLiveData : MutableLiveData() {

    fun observe(owner: LifecycleOwner, observer: Observer, isSticky: Boolean = false) {
        if (!isSticky) {
            super.observe(owner, observer)
        } else {
            super.observe(owner, CustomObserver(observer))
        }
    }


    class CustomObserver(val observer: Observer) : Observer {
        override fun onChanged(t: T) {
            //数据倒灌,在这里增加拦截逻辑
//            observer.onChanged(t)
        }
    }
}

1.增加一个参数isSticky,表示可能会发送数据倒灌,然后自己在CustomObserver增加处理逻辑

缺点:用起来不够只能,而且有可能跟业务耦合

第二种方案,通过hook修改version的值

class UnPeekLiveData : MutableLiveData() {
    override fun observe(
        owner: LifecycleOwner,
        observer: Observer
    ) {
        super.observe(owner, observer)
        hook(observer)
    }

    private fun hook(observer: Observer) {
        val liveDataClass = LiveData::class.java
        try {
            //获取field private SafeIterableMap, ObserverWrapper> mObservers
            val mObservers = liveDataClass.getDeclaredField("mObservers")
            mObservers.isAccessible = true
            //获取SafeIterableMap集合mObservers
            val observers = mObservers[this]
            val observersClass: Class<*> = observers.javaClass
            //获取SafeIterableMap的get(Object obj)方法
            val methodGet =
                observersClass.getDeclaredMethod("get", Any::class.java)
            methodGet.isAccessible = true
            //获取到observer在集合中对应的ObserverWrapper对象
            val objectWrapperEntry = methodGet.invoke(observers, observer)
            var objectWrapper: Any? = null
            if (objectWrapperEntry is Map.Entry<*, *>) {
                objectWrapper = objectWrapperEntry.value
            }
            if (objectWrapper == null) {
                throw NullPointerException("ObserverWrapper can not be null")
            }
            //获取ObserverWrapper的Class对象  LifecycleBoundObserver extends ObserverWrapper
            val wrapperClass: Class<*>? = objectWrapper.javaClass.superclass
            //获取ObserverWrapper的field mLastVersion
            val mLastVersion =
                wrapperClass!!.getDeclaredField("mLastVersion")
            mLastVersion.isAccessible = true
            //获取liveData的field mVersion
            val mVersion = liveDataClass.getDeclaredField("mVersion")
            mVersion.isAccessible = true
            val mV = mVersion[this]
            //把当前ListData的mVersion赋值给 ObserverWrapper的field mLastVersion
            mLastVersion[objectWrapper] = mV
            mObservers.isAccessible = false
            methodGet.isAccessible = false
            mLastVersion.isAccessible = false
            mVersion.isAccessible = false
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}

核心思想就是在observe的时候,将mLastVersionmVersion的值同步。

缺点:这种方式侵入式比较强,如果官方修改了源码,这里就需要跟着修改

第三种方案:通过MediatorLiveData处理

数据倒灌的原因是先发送信息,后注册,这个时候还能收到之前发送的消息,那么我们可以

将在注册之前发送的消息置为无效就可以了。

open class BaseLiveData {

    private val source = MediatorLiveData>()

    open fun post(event: T) = runOnUI {
        val eventWrapper = EventWrapper(event)
        //step 1
        source.value = eventWrapper
        //step 2
        eventWrapper.hasBeenHandled = true
    }

    fun observe(lifecycleOwner: LifecycleOwner, observer: Observer) {
        val mediator = createUnwrapMediator()

        mediator.observe(lifecycleOwner, observer)
    }

    /**
     * 获取上一次事件缓存值,可能为空
     */
    fun peekEvent(): T? {
        return source.value?.peekContent()
    }

    /**
     * 新建一个中间层. 用来筛掉那些已经被处理过的事件. 其实相当于注册一个 forever 的 observer
     */
    private fun createUnwrapMediator(): MediatorLiveData {
        val mediator = MediatorLiveData()
        mediator.addSource(source) { event ->
            //step 3                       
            if (!event.hasBeenHandled) {
                mediator.value = event.peekContent()
            }
        }
        return mediator
    }
}

class MutablePublishData : BaseLiveData() {
    public override fun post(event: T) {
        super.post(event)
    }
}

open class EventWrapper(private val content: T) {

    var hasBeenHandled = false
        internal set

    fun getContentIfNotHandled(): T? {
        return if (hasBeenHandled) {
            null
        } else {
            content
        }
    }

    fun peekContent(): T = content
}

val uiHandler by lazy {
    Handler(Looper.getMainLooper())
}

fun runOnUI(action: () -> Unit) {
    if (Looper.getMainLooper() == Looper.myLooper()) {
        action.invoke()
    } else {
        uiHandler.post(action)
    }
}

fun runOnUIDelay(delay: Long, action: () -> Unit) {
    uiHandler.postDelayed(action, delay)
}

这部分代码主要看几个部分

  1. source是原始数据源,每次post数据的时候都会给它赋值

  2. createUnwrapMediator()这里返回的是具体监听者,监听的是source这个数据源,随着source数据更新而产生回调。

  3. 回头看 step1标记的地方,如果这个时候没有注册监听者,会将hasBeenHandled标记为true,表示事件已经消费掉,也就不会产生数据倒灌的问题

  4. 如果post()信息的时候,已经有注册者了,这个时候的调用顺序为 step1->step3->step2。会先将事件发送出去,再修改hasBeenHandled的值。

补充的小知识点

  1. lambda表达式如果未持有外部类对象,那么kotlin编译器会进行单例优化。
  2. Jetpack介绍之MediatorLiveData

你可能感兴趣的:(Jetpack-LiveData)