Android Jetpack LiveData原理分析

      网上关于DataBinding,ViewModel,LiveData文章很多,最近结合源码及相关实例分析了一下,本文结合LiveData的使用来对LiveData进行源码分析。
      关于DataBinding的使用,可以参考之前的文章:
      Android JetPack DataBinding分析

一.LiveData简介

      LiveData 是一个可观察的数据持有者类。与常规 observable 不同,LiveData 是生命周期感知的,这意味着它尊重其他应用程序组件的生命周期,例如 activity,fragment。此感知确保 LiveData仅更新处于活动状态的应用组件观察者。
      如果 Observer 类表示的观察者生命周期处于 STARTEDRESUMED 状态,则 LiveData 会将其视为活动状态。LiveData 仅通知处于活动状态的观察者更新信息。非活动状态的观察者不会收到有关数据更改的通知。
      你可以注册与实现了 LifecycleOwner 接口的对象配对的观察者。此关系允许在相应 Lifecycle 对象的状态更改为 DESTROYED 时删除观察者。这对于 activity 和 fragment 特别有用,因为它们可以安全地观察 LiveData 对象而不用担心泄漏 - activity 和 fragment 在其生命周期被销毁时立即取消订阅。

二.LiveData使用

      LiveData是一个抽象类,不能直接实例话,google为我们定义好了实现类MutableLiveData,可以通过MutableLiveData来创建不同类型的对象,结合代码来看一下:

a.基础功能
private MutableLiveData mLiveData = new MutableLiveData<>();
mLiveData.observe(this, new Observer() {
    @Override
    public void onChanged(String s) {
        Toast.makeText(HookActivity.this, "receive message is " + s,Toast.LENGTH_SHORT).show();
    }
});
mLiveData.setValue("test lifecycle observe");

      通过以上可以看到,使用起来还是比较简单的,先创建一个MutableLiveData对象,执行observe()方法,传入当前UI实现类(A/F)的对象引用和observer(监听data变化),执行setValue()来更新MutableLiveData的值。

b.进阶功能

      UI内实现了对某个LiveData的监听,当UI处于后台后,此时LiveData的值进行了更新,那应该如何处理呢?结合代码来看一下:

private void testDataObserverLifecycle() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                Thread.sleep(3000);
                mLiveData.postValue("test lifecycle observe");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }).start();
}

      以上方法可以看到,是启动一个线程,然后在3s后对LiveData进行了值更新,注意一下,postValue()是在非UI线程执行的值更新调用方法,当我们在执行以上方法后,将当前界面切换到后台,3s之后再切换回来,发现会弹出toast提示。
      结论:LiveData会监听UI的生命周期变化,当处于前台后,会将值变化通知到UI

c.全局功能

      通过以上可以看到,当LiveData发生变化后,UI处于后台时,是不会收到值更新的,但是当返回前台后,会立刻收到值变化通知UI,那如果LiveData作为一个全局的变量,新的UI(A/F)启动后监听该LiveData会怎样呢?结合代码来看一下:
①.定义全局变量
      定义一个单例模式的类,里面定义一个HashMap来存储MutableLiveData,通过key来获取,如果map中存在,就返回;否则创建,然后存入map。

public final class LiveDataBus {

    private final Map> bus;

    private static class InstanceHolder {
        public static LiveDataBus sInstance = new LiveDataBus();
    }

    private LiveDataBus() {
        bus = new HashMap<>();
    }

    public static synchronized LiveDataBus getInstance() {
        return InstanceHolder.sInstance;
    }

    public  MutableLiveData with(String target, Class type) {
        if (!bus.containsKey(target)) {
            bus.put(target, new MutableLiveData<>());
        }
        return (MutableLiveData) bus.get(target);
    }
}

②.创建LiveData
      先在Activity1内使用对应key的变量,并更新值:

private void testData() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                LiveDataBus.getInstance().with("key_test", String.class).postValue("LiveDataBus test");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }).start();
}

③.使用LiveData
      后在类Activity2内使用对应key的变量:

LiveDataBus.getInstance().with("key_test", String.class).observe(this,
        new Observer() {
            @Override
            public void onChanged(String s) {
                Toast.makeText(Activity2.this, "receive message is " + s,Toast.LENGTH_SHORT).show();
            }
        });

      我们发现,会弹出Toast提示,也就是说后面创建新的UI内部使用该LiveData,也会收到回调,跟stick broadcast类似,后面注册该broadcast时,会立刻收到广播。
      在对LiveData进行使用后,有了一定的了解,带着问题去看一下LiveData的源码。

三.LiveData源码分析

a.observe()

image.png

      LiveData注册了LifecycleOwner(Activity/Fragment)生命周期的观察者,当Activity/Fragment生命周期发生变化后,LiveData会对生命周期状态进行判断,来确定是否需要通知LifecycleOwner进行逻辑更新,详情可参考Android Jetpack Lifecycle详解,注册逻辑如下:

public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
    assertMainThread("observe");
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        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()时,首先确保是主线程,如果LifeCycleOwner的生命周期是destroyed时,直接返回;然后将owner及observer封装成LifecycleBoundObserver,添加到mObservers里面,后续值发生变化时,会遍历回调;最后将wrapper添加到owner的lifecycle生命周期的观察者。


image.png

      接下来看一下LifecycleBoundObserver的实现:

class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
    .......

    @Override
    //判断owner是否处于active状态
    boolean shouldBeActive() {
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    }

    @Override
    //LifecycleEventObserver实现了LifecycleObserver,owner生命周期状态发生变化后的回调
    public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
        if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
            removeObserver(mObserver);
            return;
        }
        //当owner生命周期状态发生变化后,看是否需要将数据更新到owner,如果从后台切换到前台后,会将最新数据更新到UI[每次执行setValue()后,都会保存最新的mData = value]。
        activeStateChanged(shouldBeActive());
    }
    ......
}

      LifecycleBoundObserver实现了LifecycleEventObserver,owner有生命周期变化后,会回调onStateChanged()方法,当其生命周期变为DESTROYED后,会移除observer,这也就是为什么我们不需要手动 remove observer 的原因,此后LiveData发生变化后,不会更新到Activity/Fragment,即不会一直持有其引用,从而不会造成内存泄露;
      当Activity/Fragment处于前台后,会将最新的数据更新到UI,逻辑如下:

void activeStateChanged(boolean newActive) {
    ......
    if (mActive) {
        dispatchingValue(this);
    }
}

      感知数据变化如下:


image.png
b.setValue()/postValue()
protected void setValue(T value) {
    assertMainThread("setValue");
    mVersion++;
    mData = value;
    dispatchingValue(null);
}

protected void postValue(T value) {
    ......
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}

      执行setValue()及postValue()后,会先更新mData为最新的value,然后执行dispatchingValue()。

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

      通过以上可以看到,在执行dispatchingValue()后,会对参数进行判断,如果不为空,会单独调用considerNotify();如果为空,则会遍历调用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);
}

      通过以上可以看到,在considerNotify()内部会最终调用observer.mObserver的onChanged()方法。

d.通知途径

      以上可以看到,有两种途径会最终调用dispatchingValue():
      1.setValue():调用dispatchingValue(null),会通知所有的observer,进而再调用considerNotify()进行更新。
      2.A/F(LifeCycleOwner)的activeStateChanged():调用dispatchingValue(this),由于此处参数不为null,所以会单独回调监听该owner对应的observer。LiveData内部关联了LifecycleOwner(Activity/Fragment)生命周期相关的方法,当LifecycleOwner生命周期变化的时候都会回调onStateChanged()方法,然后会去调用activeStateChanged(),最后调用considerNotify()方法去执行数据变化回调。
      接收事件流程:


image.png

      以上就是对LiveData源码的分析,包括observe()及其内部封装、setValue()后执行dispatchValue()、considerNotify()最终执行observer的onChanged()进行通知及数据更新。

四.LiveData粘性去除

      以上实例可以看到,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);
}

      如果修改内部执行逻辑的话,可以通过hook来实现,内部有3处可以执行return,但是唯一可以hook的就是来使mLastVersion==mVersion,来使条件满足执行return,看一下实现方式:

public final class LiveDataBus {
    ......
    public  MutableLiveData with(String target, Class type) {
        if (!bus.containsKey(target)) {
            bus.put(target, new BusMutableLiveData<>());
        }
        return (MutableLiveData) bus.get(target);
    }

    private static class BusMutableLiveData extends MutableLiveData {

        @Override
        public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
            super.observe(owner, observer);
            try {
                //通过设置mLastVersion = mVersion在执行considerNotify()时返回,消除粘性
                hook(observer);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        private void hook(@NonNull Observer observer) {
            Class liveDataClass = LiveData.class;
            try {
                Field mObserversField = liveDataClass.getDeclaredField("mObservers");
                mObserversField.setAccessible(true);
                Object mObservers = mObserversField.get(this);
                Class mObserversClass = mObservers.getClass();

                Method getMethod = mObserversClass.getDeclaredMethod("get", Object.class);
                getMethod.setAccessible(true);
                Object entry = getMethod.invoke(mObservers, observer);
                Object observerWrapper = ((Map.Entry) entry).getValue();
                Class observerClass = observerWrapper.getClass().getSuperclass();

                Field mLastVersionField = observerClass.getDeclaredField("mLastVersion");
                mLastVersionField.setAccessible(true);
                Field mVersionField = liveDataClass.getDeclaredField("mVersion");
                mVersionField.setAccessible(true);
                Object mVersionValue = mVersionField.get(this);
                mLastVersionField.set(observerWrapper, mVersionValue);
            } catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
}

      以上可以看到,自定义类继承MutableLiveData类,在observe()后,执行hook(),将observer的mLastVersion的值设成跟mVersion一致就可以了。

五.LiveData 的优点:

      a.确保你的 UI 符合你的数据状态
      LiveData遵循观察者模式,状态更改时LiveData会通知 Observer对象,观察者可以在每次数据变化时更新UI。
      b.没有内存泄漏
      观察者绑定到 Lifecycle 对象,并在其相关生命周期被销毁后自行清理。
      c.不会因为 activity 停止而发生崩溃
      如果观察者的生命周期处于非活动状态(例如,activity 在后台堆栈中),则它不会接收任何 LiveData 事件。
      d.不再需要手动处理生命周期
      UI 组件只是观察相关数据,不会停止或恢复观察。LiveData自动管理所有这些,因为它在观察时意识到相关的生命周期状态变化。
      e.始终保持最新数据
      如果生命周期变为非活动状态,它将在再次变为活动状态时接收最新数据。例如,后台 activity 在返回前台后立即接收最新数据。
      f.适当的配置更改
      如果由于配置更改(例如设备旋转)而重新创建 activity 或 fragment,则会立即接收最新的可用数据。
      g.共享资源
      可以使用单例模式扩展 LiveData 对象以包装系统服务,以便可以在应用程序中共享它们。LiveData 对象连接到系统服务一次,然后任何需要该资源的观察者只需观察 LiveData 对象。
      以上是对LiveData的使用及源码分析,详细理解需要重点关注LiveData这个类

你可能感兴趣的:(Android Jetpack LiveData原理分析)