LiveData源码解析

LiveData作为jettpack的一环,常搭配ViewModel一起使用;相比于RxJava,用LiveData封装的LiveDataBus更加简洁方便,并且LiveData会感知页面的信息变化,当页面是不可见的时候,及时Data有数据更新,页面也不会接收到,然后在页面重新可见再去把数据通知给页面,而且在页面销毁时也会及时销毁数据,大大降低了内存泄露的发生;这篇主要简单分析一下LiveData的流程

1.LiveData的使用

class TestActivity :AppCompactActivity(){ 

var statusData: MutableLiveData = MutableLiveData()

override fun onCreate(savedInstanceState: Bundle?) {
    ...
    statusData.observe(this, this)
}

 override fun onChanged(t: TestLiveStatus?) {
        Log.e("TAG", "onChanged -> $t ");
    }
}

使用很方便,只需要注册一个监听,然后在监听里处理状态变化就可以

2.LiveData源码分析

2.1 livedata的注册

@MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer 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是页面的生命周期监听,主要是通过在Activity里面添加一个空的ReportFragment,监听这个Fragment的状态来实现;具体我会在下一篇中描述,这里只需要知道这个可以感知Activity的生命周期即可

这里先会创建一个LifeCycleBoundObserver ,并把owner和observer都传进去,然后用mObserv

 class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
        @NonNull
        final LifecycleOwner mOwner;

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer observer) {
            super(observer);
            mOwner = owner;
        }

        @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            activeStateChanged(shouldBeActive());
        }

        @Override
        boolean isAttachedTo(LifecycleOwner owner) {
            return mOwner == owner;
        }

        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }

这里主要关注两个方法shouldBeActiveonStateChanged

shouldBeActivite个枚举判断,如果枚举的类型比STARTED大则返回true

 public boolean isAtLeast(@NonNull State state) {
            return compareTo(state) >= 0;
        }

我们看一下这个State的声明

public enum State {

    DESTROYED,
    INITIALIZED,
    CREATED,
    STARTED,
    RESUMED 

    public boolean isAtLeast(@NonNull State state) {
            return compareTo(state) >= 0;
        }
}

STARTED大的只有RESUME

LifeCycle和这个State的有个对应关系可以参考一下,所以我们可以认为这个shouldBeActive返回的是表示是页面是否是从不可见变成了可见状态

 static State getStateAfter(Event event) {
        switch (event) {
            case ON_CREATE:
            case ON_STOP:
                return CREATED;
            case ON_START:
            case ON_PAUSE:
                return STARTED;
            case ON_RESUME:
                return RESUMED;
            case ON_DESTROY:
                return DESTROYED;
            case ON_ANY:
                break;
        }
        throw new IllegalArgumentException("Unexpected event value " + event);
    }

onStateChanged中包含两部分

1.当页面被销毁时,注册的观察者被清除,后续的事件通知也随之终止

2.当页面非销毁状态时,处理相应的状态变化逻辑

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);
            }
        }

可以看出,这个方法只处理活跃状态变化的,而从上面的分析,可以认为就是页面可见性变化的处理

默认mActiveCount = 0 , 每次从不可见变成可见+1,而从可见变成不可见-1

onActive和onInactive则分别是处理这两种状态的方法,这里这两个都是空实现

最后的当变成可见后 会调用 dispatchingValue 通知消息更新

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;
    }

这里虽然有改while循环,但大部分情况下只会执行一次,因为mDispatchInvalidated一进来就会设置成false ; 对于并发情况会执行多次,因为在入口处并发会重新设置成true

有两种情况,initiator为空和不为空,为空是通知所有的观察者,不为空则是通知传入的initiator;

主要差异是主动和被动

为null主要场景是setValue等主动设置值的情况,会同步更新所有注册的监听

不为null的主要场景是状态变更,每个observer自己去刷新数据

然后我们看一下considerNotify方法

 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);

这里会先判断是否是活跃的,不活跃的直接返回

再判定状态是否resume的,不是的话就回到上面的状态变更方法;这里相当于做了活跃的二次判断

然后判断mLastVersionmVersion的大小,只有mVersion比mLastVersion大才会去通知observer去观察数据,同时把mLastVersion赋值成新的值;这个主要是避免重新分发,如果没这个判断,则每次从不可见变成可见都会分发一次最新的消息,这肯定不是我们所想要的结果

然后设置值的方法

    @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

在这里会把mVersion++ , 并调用上面的dispatchingValue(null)方法通知所有的observer

注意的是

 static final int START_VERSION = -1;

 private int mVersion = START_VERSION;


 private abstract class ObserverWrapper {
        int mLastVersion = START_VERSION;
        ...

}

初始值mVersion和mLastVersion都是 -1 ,而LiveData有两个构造方法区别一下

  public LiveData(T value) {
        mData = value;
        mVersion = START_VERSION + 1;
    }

    /**
     * Creates a LiveData with no value assigned to it.
     */
    public LiveData() {
        mData = NOT_SET;
        mVersion = START_VERSION;
    }

无参的构造方法mVersion=-1,而传一个data数据的mVersion=0

就是说,有数据的构造方法,初始值判断 mVersion> mLastVersion是成立的,而无参的是不成立的

此外,因为setValue会使mVersion++, 如果在注册观察者之前就调用了setValue方法,那么在注册后,页面变成可见的情况下,会强制把之前set的值刷新到方法回调中,正常来说没有问题;

但在我们设计LiveDataBus总线消息机制的时候,很明显是不符合消息的流程的,不论是Rxjava还是EventBus都是不允许接收到注册前的信息的

具体修改得依赖反射,自定义LiveData继承自MutableLiveData,重写observer方法

  @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer 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);
    }

反射修改LiveData的mVersion值,然后通过反射拿到wrapper对象,反射修改这个对象的mLastVersion值

常规LiveDataBus配置

public class LiveDataBus {
    private static LiveDataBus instance = new LiveDataBus();
    private Map map = new HashMap<>();

    public static LiveDataBus getInstance() {
        return instance;
    }

    public  MLiveData getLiveData(String key, Class type) {
        if (!map.containsKey(key)) {
            map.put(key, new MLiveData());
        }
        return (MLiveData) map.get(key);
    }

    public void remove(String key) {
        map.remove(key);
    }
}

public class MLiveData extends MutableLiveData {}

页面配置

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_live_data_bus);
        findViewById(R.id.btn_click).setOnClickListener(this);
        textView = findViewById(R.id.tv_msg);
        liveData = LiveDataBus.getInstance().getLiveData("1234", String.class);
        liveData.setValue("aaa");
        liveData.setValue("bbbb");
        liveData.observe(this, x -> {
                    textView.setText(x + "");
                }
        );
    }

这时候进来,页面会直接显示文字 "bbbb" ,但我们注册是在发送之后,不应该接收到前面的消息

然后我们反射修改成这个样式就可以了

public class MLiveData extends MutableLiveData {
    @Override
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
        super.observe(owner, observer);
        reflect(observer);
    }

    private void reflect(Observer observer) {
        try {
            Field mObserversField = LiveData.class.getDeclaredField("mObservers");
            mObserversField.setAccessible(true);
            Object mObservers = mObserversField.get(this);

            Method getMethod = mObservers.getClass().getDeclaredMethod("get", Object.class);
            getMethod.setAccessible(true);
            Object observerEntry = getMethod.invoke(mObservers, observer);
            //这个值获取到的是 SafeIterableMap.Entry 实现了Map.Entry接口,需要再次获取
            //而HashMap中
            // public V get(Object key) {
            //        Node e;
            //        return (e = getNode(hash(key), key)) == null ? null : e.value;
            //}
            // 可以看出帮我们自动获取了value的属性

            Map.Entry entry = (Map.Entry) observerEntry;
            Object observerWrapper = entry.getValue();
            Field mLastVersionField = observerWrapper.getClass().getSuperclass().getDeclaredField("mLastVersion");
            mLastVersionField.setAccessible(true);

            Field mVersionField = LiveData.class.getDeclaredField("mVersion");
            mVersionField.setAccessible(true);
            Object mVersion = mVersionField.get(this);
            mLastVersionField.set(observerWrapper,mVersion);


        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

注意mObserver的get方法获取到的并不是实际的值

private SafeIterableMap, ObserverWrapper> mObservers =
            new SafeIterableMap<>();

这个集合的get方法返回的是一个节点的信息

 protected Entry get(K k) {
        Entry currentNode = mStart;
        while (currentNode != null) {
            if (currentNode.mKey.equals(k)) {
                break;
            }
            currentNode = currentNode.mNext;
        }
        return currentNode;
    }

  需要再次调用获取value方法获取真正的值

而HashMap中

public V get(Object key) {
        Node e;
        return (e = getNode(hash(key), key)) == null ? null : e.value;
}

可以看出帮我们自动获取了value的属性,这两点区分一下

其他一点东西

LiveData中有一个额外的注册方法,observerForever方法,注意这里不需要LifecycleOwner传入,是和页面无关的,而且一注册马上会调用activeStateChanged(true)方法,上面也说到了,这里就认为页面从不活跃变更为活跃状态,并把活跃值置为true,因为是周期无关,这个值后续一直会是true, 而在这里的方法相当于马上接收到最新的消息;

@MainThread
    public void observeForever(@NonNull Observer observer) {
        assertMainThread("observeForever");
        AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing instanceof LiveData.LifecycleBoundObserver) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        wrapper.activeStateChanged(true);
    }

而且这个类的活跃判断方法被重写为true

private class AlwaysActiveObserver extends ObserverWrapper {

        AlwaysActiveObserver(Observer observer) {
            super(observer);
        }

        @Override
        boolean shouldBeActive() {
            return true;
        }
    

而在上面的considerNotify方法中,这两个方法的判定就始终是不满足的,所以一直会执行消息发布

 if (!observer.mActive) {
    return;
  }

 if (!observer.shouldBeActive()) {
      observer.activeStateChanged(false);
      return;
}

LiveData总结

1.通过observe方法注册并传入当前Activity信息,可以感知当期页面生命周期变化;

当页面销毁时候清除所有注册并直接退出;

当页面从不可见变成可见时,检测数据的Version, 根据具体的比较值判断是否发送最新消息给观察者对象,判断标准是当mVersion> mLastVersion 则发送,并把mLastVersion同步成mVersion值,而这两个对应的初始值都是-1;

mVersion归属LiveData,而mLastVersion归属ObserverWrapper,对应于上面创建的LifecycleBoundObserver,反射时候需要注意;

引入Version判断是为了避免重复发送数据,当活跃状态频繁变更而数据未变更导致的多次刷新;

可见性状态判断只要是根据声明的枚举类型,当前状态和STARTED状态进行对比,大于这个状态即RESUME状态则认为是从不可见变成可见,反之则是可见变成不可见,这个属于被动更新;可见性又可以称为活动状态,意思都差不多

2. 通过setValue或postValue方法通知所有注册的观察者数据发生了更新,这个是主动更新,但仍受页面可见性状态影响,非可见状态并不会通知数据更新,需要等下次页面活动状态变更才去刷新;

每次通知都会把当前LiveData的数据版本mVersion++,不论是被动还是主动更新都必须满足version判定规则;

setValue在主线程中调用,postValue在子线程中调用

3.当注册前就已经发送了消息更新数据,那么注册后第一次活跃状态变更就会把这个数据刷新给观察对象;

正常流程无需关心,但涉及消息总线处理则需要额外反射处理LiveData,一般自定义继承MutableLiveData,在注册的时候将传入的对象的observer中的mLastVersion更改为LiveData中的mVersion值,这样注册之前的数据变更消息便不会接收

4.如果不需要关注页面信息,只用来提示消息更新,则可以用observerForever方法

补上一张大致关系图

LiveData源码解析_第1张图片

 

 

你可能感兴趣的:(Android)