Android 理解LiveData内部及使用

概述

LiveData是实现MVVM的关键组件。LiveData基于观察者模式,是一个观察者主体的数据持有类。

不同于普通的观察者主体,LiveData是对生命周期敏感的,即它能感知activity、fragment或service等组件的生命周期。因此可以在适当的时刻结合ViewModel和底层数据存储修改前台与数据相关的UI。

LiveData封装在ViewModel中使用。ViewModel的生命周期与创建它的组件UI一致,且ViewModel能在因配置改变而导致的activity销毁、重建的过程中存活,避免了数据的重复创建,提高了性能,是实现数据和UI解耦的关键组件。

本文目的

  • 通过分析源码,了解LiveData运行机制(生命周期监督和数据更新);
  • 学会使用MutableLiveData、MediatorLiveData;

LiveData机制

1 相互观察

1.1 相互绑定

通过observe()方法绑定UI组件和观察者;

    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        assertMainThread("observe");//必须在主线程中调用
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            return;
        }
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        ......
        ......//省略代码,检测是否重复插入和冲突处理
        owner.getLifecycle().addObserver(wrapper);//wrapper将观察UI组件的生命周期
    }

这里能够很清晰的看到观察者模式——向mObservers中添加一个wrapper(封装了UI组件和观察者);

wrapper本身也是个观察者,它将观察UI组件的生命周期变化(最后一行代码);

这个简单的方法实现了LiveData和UI组件的相互观察。

1.2 LiveData对UI组件生命周期的监督

LifecycleBoundObserver也实现了Observable接口:

       @Override
        public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
            //当UI组件被销毁时,LiveData会自己销毁注册的观察者,所以不必担心内存泄露问题
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            activeStateChanged(shouldBeActive());
        }

LiveData会自己解除已不再栈中的UI组件,所以我们不必担心内存泄露问题。

void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {//状态不变,直接返回
                return;
            }
            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);
            }
        }

当状态没变时,直接返回;

如果当前状态为active,且观察者数目从0变为1,则会调用onActive回调;

若当前状态不是active且观察者数目仍为0,则调用onInactive回调。MutableLiveData中开发者可自己实现上述回调。

最后dispatchingValue()传递并更新数据。上述即为LiveData对UI组件生命周期监测的处理流程。

1.3 小结

  • LiveData和UI组件是相互观察;
  • LiveData不会向被paused、stopped和destroyed的UI组件发送数据更新信息,不用担心处理这些组件可能的crash;
  • 当组件被destroyed后,LiveData会自己移除被销毁的组件观察者,不用担心内存泄露。
  • 在MutableLiveData中,我们可以自己实现onActive和onInactive,做一些定制开发;但是有的组件,如MediatorLiveData,在这两个方法中有自己特定的逻辑。

(图片来源:https://medium.com/@elye.project/understanding-live-data-made-simple-a820fcd7b4d0

2 数据更新

从LiveData.setValue()着手:

    //该方法需在主线程中调用
    @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

dispatchingValue():

void dispatchingValue(@Nullable ObserverWrapper initiator) {
        ......
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
                //监听UI状态变化时的更新逻辑
                considerNotify(initiator);
                initiator = null;
            } else {
                //LiveData主动调用setValue()更新逻辑
                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();

private void considerNotify(ObserverWrapper observer) {
        //再次映射组件非active,不会更新数据
        if (!observer.mActive) {
            return;
        }
        //active的管理
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        //状态版本管理
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        //调用观察者的更新方法
        observer.mObserver.onChanged((T) mData);
    }

逻辑一目了然,不再多说。

使用不同LiveData

1 MutableLiveData

最简单的LiveData,封装在ViewModel内部:

public class MyViewModel extends ViewModel {

private MutableLiveData<Integer> mNormalData = new MutableLiveData<>();

......

//注册观察者
public void observeNormal(LifecycleOwner owner, Observer observer) {
        mNormalData.observe(owner, observer);
}

......

   //更新数据
   public void increment() {
        Integer value = mNormalData.getValue();
        if (value == null || value == 0) {
            mNormalData.setValue(1);
        } else {
            mNormalData.setValue(++value);
        }
   }

......

}//class ends

Observer:

//匿名内部类会持有外部类的引用,可能造成内存泄露,但对LiveData无碍;
//通过回调更新UI
private Observer getObserver() {
        if (mObserver == null) {
            mObserver = new Observer() {
                @Override
                public void onChanged(Object o) {
                    if (o instanceof Integer) {
                        mViewText.setText(String.valueOf(o));
                    }
                }
            };
        }
        return mObserver;
    }

2 MediatorLiveData

MediatorLiveData扮演了一个数据容器的角色,多个数据源可绑定至MediatorLiveData,从而多个数据源的改变可应用到UI。

2.1 使用

数据成员封装在ViewModel中:

public class CounterViewModel extends ViewModel {

    private MediatorLiveData<String> mMediator = new MediatorLiveData<>();
    private MutableLiveData<Integer> mMergeA = new MutableLiveData<>();
    private MutableLiveData<Integer> mMergeB = new MutableLiveData<>();

    private MergerObserver mObserverA = new MergerObserver() {
        @Override
        public void onChanged(Object o) {
            super.onChanged(o);
            if (o instanceof Integer) {
                StringBuilder sb = new StringBuilder();
                sb.append("A: ").append( o);
                mMediator.setValue(sb.toString());
            }
        }
    };

    private MergerObserver mObserverB = new MergerObserver() {
        @Override
        public void onChanged(Object o) {
            super.onChanged(o);
            if (o instanceof Integer) {
                StringBuilder sb = new StringBuilder();
                sb.append("B: ").append( o);
                mMediator.setValue(sb.toString());
            }
        }
    };
}

通过addSourcej将子数据源绑定到MediatorLiveData:

    private void initMediator() {
        mMediator.addSource(mMergeA, mObserverA);
        mMediator.addSource(mMergeB, mObserverB);
    }

MediatorLiveData和外部UI组件绑定;

    public void observeMediator(LifecycleOwner owner, Observer observer) {
        mMediator.observe(owner, observer);
    }

当mMergeA或mMergeB的数据变化时,会调起其观察者(mObserverA、mObserverB)的回调;

观察者的回调实现很重要,对数据进行处理后,必须更新MediatorLiveData的数据,从而才会引起在UI端的回调。

MediatorLiveData是一种双重观察的模式:ObserverA和ObserverB分别观察源数据A和B;UI组件端观察MediatorLiveData。在ObserverA和ObserverB得到更新数据时,必须在回调中处理数据且更新MediatorLiveData(即调用MediatorLiveData.setValue()),从而调起UI端回调。

(图片来源:https://medium.com/@elye.project/understanding-live-data-made-simple-a820fcd7b4d0

2.2  MediatorLiveData源码解读

从添加数据源addSource()看起:

    @MainThread
    public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
        //创建Source对象,并添加到mSource中;
        Source<S> e = new Source<>(source, onChanged);
        Source<?> existing = mSources.putIfAbsent(source, e);
        ......
        ......//检查重复和冲突
        //MediatorLiveData未绑定观察者时,不会调用
        if (hasActiveObservers()) {
            e.plug();
        }
    }

Source封装了数据源和观察者,且Source自己实现了观察者接口。该步骤主要逻辑就是往mSource里添加Source对象。

MediatorLiveData使用的是LiveData的observe()(如前所述),但是其在初次添加了观察者的回调里有自己的实现逻辑:

    protected void onActive() {
        for (Map.Entry<LiveData<?>, Source<?>> source : mSources) {
            source.getValue().plug();
        }
    }

遍历了每个Source,并调用其plug()方法,其中直接调用了LiveData.observeForever()

    @MainThread
    public void observeForever(@NonNull Observer<? super T> observer) {
        assertMainThread("observeForever");
        AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        ......
        ......//检查重复和冲突
        wrapper.activeStateChanged(true);
    }

与observe()不同的是,其中wrapper类型不一样,为AlwaysActiveObserver:

   private class AlwaysActiveObserver extends ObserverWrapper {

        AlwaysActiveObserver(Observer<? super T> observer) {
            super(observer);
        }

        @Override
        boolean shouldBeActive() {
            return true;
        }
    }

所以该Observer永远都是active的。

所以,plug()方法就是将各个数据源和它对应的观察者建立了观察的关系。

2.3  MediatorLiveData小结

  • MediatorLiveData作为LiveData的容器,以及与外部交流的接口;
  • MediatorLiveData的内部数据源更新时,必须在回调中更新MediatorLiveData,才能实现数据传递。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值