Android Architecture Component之L

作者: gdutkyle | 来源:发表于2018-08-02 22:18 被阅读10次

    一 什么是LiveData

    LiveData是一个可观察数据变化的类,但是与其他观察类不同的是,LiveData是可以感知到所持有类的生命周期的。所以我们一般用它来和Activity、Fragment或者service一起使用。这里有个很有好处的地方就是,LiveData的onChange方法,只会在activity在前台的时候产生回调,后面我们可以用例子来说明。

    二 LiveData的好处

    那么使用LiveData有什么好处呢?从LiveData的相关特性,我们可以归纳出以下几点:

    1 确保UI和数据状态保持一致
    LiveData遵循观察者模式,当生命周期发生改变的时候,LiveData会通知观察者对象。因此我们可以通过统一在观察者对象数据中更新UI,而不是通过app数据的变更去改变UI。在我们这些对象发生变更的时候,我们的UI也会跟着改变。

    2 不会有内存泄漏
    所有的观察者都是绑定到owner的生命周期内的,也就是说,如果owner被finish的时候,所有的观察者也会被自动销毁。炒鸡智能方便有木有?

    3 不会因为Activity被销毁而导致崩溃
    这种情况多数发生在我们的异步回调函数中,比如有时候我们回去通过异步线程来获取网络数据后,刷新我们的界面。这个时候,当我们的activity被销毁的时候,我们的异步线程回调才刚回来,这就导致了我们在一个废弃的activity中更新他的UI,这就会导致异常崩溃的发生。

    4 不再需要手动去控制生命周期
    UI组件只会在对象不是stop或者resume的时候进行观察,LiveData会自动管理这一切。在正确的时候,给与观察者以回调。

    5 永远保持最新的数据状态
    当观察的对象不是处于激活状态的时候,LiveData并不会去刷新数据,而当观察的对象重新激活的时候,那么LiveData将会刷新最新的数据。最典型的是,如果你的Activity是后台的时候,再次期间所有的数据变更,liveData都会选择性的忽略,等到你重新唤醒Activity的时候,LiveData马上就会刷新他的值,让他和最后一个setValue(value)保持一致。

    三 开始源码之旅

    接下来,我们从一段简单的源码开始

    viewModel.loadFiveUsers().observe(MainActivity.this, new Observer<List<User>>() {
            @Override
            public void onChanged(@Nullable List<User> users) {
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < users.size(); i++) {
                    User user = users.get(i);
                    sb.append("====================\n");
                    sb.append("uid:" + user.getUid() + "\n " + user.getUserName() + "\n" + user.getLastName() + "\n");
                    sb.append("\n");
                }
                tv_values.setText(sb.toString());
            }
        });
    

    我们这里暂且忽略viewModel部门,我们只需要知道,viewModel.loadFiveUsers()返回的是一个LiveData<T>类型的数据就可以了。简单的说一下这段代码,就是实时获取当前数据库中的前5条数据,并且把这5条数据通过TextView显示出来。业务场景其实非常的简单。好了,接下来开始拆轮子

    第一步:LiveData.observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer)Owner和observe是如何建立联系的
    我们进入源码的世界

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

    首先,LiveData强调的是,observe方法必须是在UI线程中进行调用的。我们从源码可知
    1 如果当前的owner是Destroyed状态的,那么我们就直接忽略掉了,这个是显而易见的。
    2 LiveData会先将当前的owner和observe结合在一起,生成一个wrapper对象,然后尝试observe和wrapper当成key和value 添加进mObservers中,这个mObservers其实就是一个map对象。如果发现这个key对应的value已经有值了,并且这value并不是我们即将put进去的value,那么就会抛错
    3 加入不存在的话,那么wrapper将会被添加进当前owner的生命周期中,进行监听。

    第二步:setValue(T value)
    LiveData提供了两个setValue的方法,一个是同步情况的调用

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

    另一个是异步情况的调用

    protected void postValue(T value) {
    boolean postTask;
    synchronized (mDataLock) {
       postTask = mPendingData == NOT_SET;
        mPendingData = value;
       }
       if (!postTask) {
           return;
       }
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }  
    

    其实最后都是调用了 setValue((T) newValue);方法。我们来研究下这个方法,可以看到,他会先判断当前是否在主线程调用,如果不是的话,那么就会抛出错误。然后就会把当前LiveData的版本号mVersion++,把mData设置成最新的value。其实整个过程最麻烦的是dispatchingValue(null)这个方法。我们进入这个方法进行查看

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

    其实我们可以看到,这个个方法就是现在已有的观察者进行循环,检查到如果是当前的观察者,那么就调用considerNotify(iterator.next().getValue())方法。也即是找到最新的mData,进行onchanged(mData)回调给观察者。

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

    其实这个方法,会调用到

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

    这个方法就是会去判断当前的owner的状态是否是active状态,进行是否分发的动作。

    四 生命周期中LiveData的回调情况

    1 关于:永远保持最新的数据状态

    我们主动setValue(T value)方法后,liveData调用的onChanged(T value)流程已经分析完毕了,那么前面我们所说的,当观察的对象不是处于激活状态的时候,LiveData并不会去刷新数据,而当观察的对象重新激活的时候,那么LiveData将会刷新最新的数据。最典型的是,如果你的Activity是后台的时候,再次期间所有的数据变更,liveData都会选择性的忽略,等到你重新唤醒Activity的时候,LiveData马上就会刷新他的值,让他和最后一个setValue(value)保持一致。这个是怎么实现的呢?

    LifecycleBoundObserver 生命周期回调
    其实就是如上图所说的,我们的activity在后台或者重新回到前台的时候,都会回调到上面的onStateChanged()方法。当Activity是后台的时候,shouldBeActive返回的是false,那么
    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(this)就不会进行分发,从而不会触发observe的onchanged(T mData) 方法。

    2 Activity finish的时候,移除监听

    上面的图中我们可以看到,LiveData还会去判断当前的owner是否已经被销毁了,如果被销毁了,还会调用removeObserver(mObserver);方法,这也就是我们不需要去关心内存泄漏,或者在Activity finish情况下,还去尝试更新UI的问题。

    自此,LiveData的完整分析已经完成。

    相关文章

      网友评论

        本文标题:Android Architecture Component之L

        本文链接:https://www.haomeiwen.com/subject/akkevftx.html