【Android JetPack系列】LiveData

原创
2019/10/24 14:28
阅读数 144

一、前言

1、什么是 LiveData

LiveData 是一个数据持有类。它具有以下特点:

  • 数据可以被 观察者 订阅;
  • 能够感知组件( Fragment、Activity、Service ) 的生命周期;
  • 只有在 组件 处于 激活状态才会通知观察者有数据更新;

2、LiveData 能为我们做什么

  • 能够保证 数据 和 UI 统一LiveData 采用了 观察者模式,LiveData 是被观察者,当数据有变化时会通知 UI

  • 减少内存泄露LiveData 能够感知到组件的生命周期,当组件处于 销毁(destroyed) 状态时,观察者对象会被清除,当 Activity 停止时不会导致 crash ,因为 组件处于非激活状态时,不会收到 LiveData中数据变化的通知。

  • 组件和数据相关的内容能够实时更新。组件在前台的时候能够实时收到数据改变的通知,当组件从后台切换到前台时,LiveData 能够将最新的数据通知组件,因此保证了组件中和数据相关的内容能够实时更新。

  • 解决横竖屏切换(configuration change)数据问题。在屏幕发生旋转时,不需要额外的处理来保存数据,当屏幕方向变化时,组件会被 recreate,然而系统并不能保证你的数据能够被恢复。当采用 LiveData 保存数据时,因为数据和组件分离了,当组件被 recreate ,数据还是存在 LiveData 中,并不会被销毁。

  • 资源共享。如果对应的 LiveData 是单例的话,就能在 App 的组件间分享数据;这部分详细的信息可以参考 继承 LiveData

二、简单使用

1、创建LiveData

LiveData 的2种创建方式:

  • 直接使用MutableLiveData对象;
  • 自行继承 LiveData 类。

1.1、直接使用 MutableLiveData

  MutableLiveData<String> data = new MutableLiveData<>();

1.2、继承 LiveData

2、创建并订阅观察者

LiveData 通过 observe()方法注册观察者。观察者这里使用匿名方式:

// 写于MainActivity
data.observe(this, new Observer<String>() {
            @Override
            public void onChanged(@Nullable String s) {
                Toast.makeText(MainActivity.this,s,Toast.LENGTH_SHORT).show();
            }
        });

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

observe方法接收 2 个参数:

  • 一个是具有生命周期的 LifecycleOwner;
  • 另一个是观察者 Observer<T>.

首先判断 LifecycleOwner 当前的生命周期是否为 Destroyed

  • 如果是则直接 return
  • 如果不等于Destroyednew 了一个内部类 LifecycleBoundObserver 对象并且构造方法传入了具有生命周期的 LifecycleOwner和 观察者。看下源码:
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
        @NonNull final LifecycleOwner mOwner;

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

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

        @Override
        public void onStateChanged(LifecycleOwner source, 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);
        }
    }

LifecycleBoundObserver 继承自 ObserverWrapper,并实现 GenericLifecycleObserver,而 GenericLifecycleObserver 继承了 LifecycleObserver接口。

由此可以看出LifecycleBoundObserver类就是把Observer 和生命周期关联起来。

再看此类,我们先看 onStateChanged()方法,当生命周期变化时会回调,如果getCurrentState() == DESTROYEDremoveObserver,反之则调用父类ObserverWrapperactiveStateChanged()方法:

 private abstract class ObserverWrapper {
        final Observer<T> mObserver;
        boolean mActive;
        int mLastVersion = START_VERSION;

        ObserverWrapper(Observer<T> observer) {
            mObserver = observer;
        }

        abstract boolean shouldBeActive();

        boolean isAttachedTo(LifecycleOwner owner) {
            return false;
        }

        void detachObserver() {
        }

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

分析activeStateChanged():

  • 首先判断 activeState新旧状态是否相同,不同则把新的状态赋给 mActive,是生命周期状态处于ACTIVE情况下的逻辑处理。如果新的状态和旧的状态相同则直接返回。

  • 这里有个常量 LiveData.this.mActiveCount,看注释可以理解为观察者处于活动状态 个数。

  • 往下看 if (wasInactive && mActive)。 如果 mActiveCount=0 并且 mActivetrue,即观察者处于活动状态。

    • 个数从 0 变为 1 个则调用 onActive(); 观察者处于活动状态
    • 个数从1 变为 0 时则调用 onInactive()

然而onActive()onInactive()并没有任何实现代码。好了,接下来继续往下看dispatchingValue(this);应该就是数据变化消息调度。源代码:

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

前面的几行if 判断姑且先不看,先看从if(initiator != null)开始看,如果initiator!= null调用considerNotify(initiator)方法;源代码:

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

最后一行代码 observer.mObserver.onChanged((T) mData); Observer的数据变化回调;

好了我们再回过头看看initiator == null的逻辑:

for (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
                    break;
                }
            }

如果initiator == null 则会通过迭代器mObservers 遍历获取 ObserverWrapper,最终还是调用 considerNotify 方法;既然有取 ObserverWrapper,咋们再看看在哪儿存的:

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

mObservers.putIfAbsent(observer, wrapper) 存入容器中,mObservers.putIfAbsent 这个添加数据的方式貌似很少见,于是乎在看看 mObservers是个什么数据容器,成员变量中:

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

SafeIterableMap 有以下特性:

  • 支持键值对存储,用链表实现,模拟成 Map 的接口
  • 支持在遍历的过程中删除任意元素,不会触发ConcurrentModifiedException
  • 非线程安全

最后 addObserver 添加注册。

3、发起数据通知

发起数据通知 2 种方式:

  • postValue
  • setValue
    data.postValue("Hello LiveData");
 // data.setValue("Hello LiveData");

MutableLiveData源码:

public class MutableLiveData<T> extends LiveData<T> {
    @Override
    public void postValue(T value) {
       super.postValue(value);
    }

   @Override
   public void setValue(T value) {
       super.setValue(value);
   }
 }

我们先看看setValue 代码:

    @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }
  private static void assertMainThread(String methodName) {
        if (!ArchTaskExecutor.getInstance().isMainThread()) {
            throw new IllegalStateException("Cannot invoke " + methodName + " on a background"
                    + " thread");
        }
    }

assertMainThread("setValue");则是判断是否在主线程。

所以貌似**setValue 方式必须在主线程中执行,如果非主线程则抛出异常。 **

再看看postValue:

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

postValue调用postToMainThread方法,最终还是用过setValue方式:

    private final Runnable mPostValueRunnable = new Runnable() {
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            //noinspection unchecked
            setValue((T) newValue);
        }
    };

因此最终明白为什么 setValue 方法只能在主线程中调用,postValue 可以在任何线程中调用,如果是在后台子线程中更新 LiveData的值,必须调用postValue

三、高级应用

1、 LiveDataBus 的设计和架构

LiveDataBus源码

LiveDataBus 的组成

  • 消息 消息可以是任何的Object,可以定义不同类型的消息,如BooleanString。也可以定义自定义类型的消息。

  • 消息通道
    LiveData扮演了消息通道的角色,不同的消息通道用不同的名字区分,名字是String类型的,可以通过名字获取到一个LiveData消息通道。

  • 消息总线
    消息总线通过单例实现,不同的消息通道存放在一个HashMap中。

  • 订阅
    订阅者通过getChannel获取消息通道,然后调用observe订阅这个通道的消息。

  • 发布
    发布者通过getChannel获取消息通道,然后调用setValue或者postValue发布消息。

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部