Jetpack-LiveData原理解析

前言

LiveData 组件是 Jetpack 推出的基于观察者的消息订阅/分发组件,具有宿主(Activity、Fragment)生命周期感知能力,这种感知能力可确保 LiveData 仅分发消息给处于活跃状态的观察者,即只有处于活跃状态的观察者才能收到消息,并在 Lifecycle 处于无效状态(DESTROYED)时自动移除数据监听行为,从而避免常见的内存泄露和 NPE 问题(观察者模式)

LiveData 的消息分发机制,是以往的 Handler、EventBus、RxjavaBus 无法比拟的,它们不会顾及当前页面是否可见,一股脑的有消息就转发。导致即便应用在后台页面不可见的情况下还在做一些无用的工作抢占资源

Google LiveData 介绍

LiveData引入工程

implementation "androidx.lifecycle:lifecycle-livedata:2.2.0"

LiveData核心类和方法介绍

MutableLiveData

在使用 LiveData 的做消息分发的时候,需要使用这个子类。之所以这么设计,是考虑到单一开闭原则,只有拿到 MutableLiveData 对象才可以发送消息,LiveData 对象只能接收消息,避免拿到 LiveData对象时既能发消息也能收消息的混乱使用 (设计原则:职责单一

@SuppressWarnings("WeakerAccess")
public class MutableLiveData<T> extends LiveData<T> {

    public MutableLiveData(T value) {
        super(value);
    }

    public MutableLiveData() {
        super();
    }

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

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

MediatorLiveData

可以统一观察多个 LiveData 发射的数据进行统一的处理。同时也可以做为一个 LiveData,被其他 Observer 观察

public class MediatorLiveData<T> extends MutableLiveData<T> {
  private SafeIterableMap<LiveData<?>, Source<?>> mSources = new SafeIterableMap<>();
  
  //添加观察者
  @MainThread
  public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
     //将被观察者 和观察者 包装成一个 Source对象 添加到map中 且只能添加一次
      Source<S> e = new Source<>(source, onChanged);
    
      Source<?> existing = mSources.putIfAbsent(source, e);
      if (existing != null && existing.mObserver != onChanged) {
          throw new IllegalArgumentException(
                  "This source was already added with the different observer");
      }
      if (existing != null) {
          return;
      }
      //判断页面状态是否在活动状态
      if (hasActiveObservers()) {
          e.plug();
      }
  }

  @MainThread //移除被观察者 并移除观察者监听
  public <S> void removeSource(@NonNull LiveData<S> toRemote) {
      Source<?> source = mSources.remove(toRemote);
      if (source != null) {
          source.unplug();
      }
  }

  @CallSuper
  @Override //活动状态 统一为所有Source添加观察者
  protected void onActive() {
      for (Map.Entry<LiveData<?>, Source<?>> source : mSources) {
          source.getValue().plug();
      }
  }

  @CallSuper
  @Override //活动状态 统一为所有Source移除观察者监听
  protected void onInactive() {
      for (Map.Entry<LiveData<?>, Source<?>> source : mSources) {
          source.getValue().unplug();
      }
  }

  private static class Source<V> implements Observer<V> {
      final LiveData<V> mLiveData;
      final Observer<? super V> mObserver;
      int mVersion = START_VERSION;

      Source(LiveData<V> liveData, final Observer<? super V> observer) {
          mLiveData = liveData;
          mObserver = observer;
      }
      //liveData添加 观察者
      void plug() {
          mLiveData.observeForever(this);
      }
      //liveData移除 观察者
      void unplug() {
          mLiveData.removeObserver(this);
      }

      @Override
      public void onChanged(@Nullable V v) {
          if (mVersion != mLiveData.getVersion()) {
              mVersion = mLiveData.getVersion();
              mObserver.onChanged(v);
          }
      }
  }

统一观察多个 LiveData 发射的数据进行统一的处理

//创建两个长得差不多的LiveData对象
LiveData<Integer> liveData1 =  new MutableLiveData();
LiveData<Integer> liveData2 = new MutableLiveData();

//再创建一个聚合类MediatorLiveData
MediatorLiveData<Integer> liveDataMerger = new MediatorLiveData<>();
//分别把上面创建LiveData 添加进来。
liveDataMerger.addSource(liveData1, observer);
liveDataMerger.addSource(liveData2, observer);

Observer observer = new Observer<Integer>() {
@Override
public void onChanged(@Nullable Integer s) {
    titleTextView.setText(s);
}
//一旦liveData1或liveData2发送了新的数据 ,observer便能观察的到,以便  统一处理更新UI

Transformations

Transformations 是用于 LiveData 类的转换。
可以使用转换方法在观察者的整个生命周期中传递信息。 除非观察者观察返回的 LiveData 对象,否则不计算转换。由于转换是延迟计算的,因此与生命周期相关的行为将隐式传递,而无需其他显式调用或依赖项

Google Transformations 介绍

public class Transformations {

    private Transformations() {
    }
    /**LiveData<User> userLiveData = ...;
      *LiveData<String> userFullNameLiveData =
      *Transformations.map(
      *    userLiveData,
      *    user -> user.firstName + user.lastName);
      })*/
    //将主线程上的给定函数应用于 LiveData 数据源发出的每个值,
    //然后返回 LiveData,来发出结果值。给定的函数 func 将在主线程上执行
    @MainThread
    @NonNull
    public static <X, Y> LiveData<Y> map(
            @NonNull LiveData<X> source,
            @NonNull final Function<X, Y> mapFunction) {
        //监听 source 的变化 获取 source 的值 在通过 mapFunction 返回新的值 set给 result
        final MediatorLiveData<Y> result = new MediatorLiveData<>();
        result.addSource(source, new Observer<X>() {
            @Override
            public void onChanged(@Nullable X x) {
                result.setValue(mapFunction.apply(x));
            }
        });
        return result;
    }

   
    @MainThread
    @NonNull
    public static <X, Y> LiveData<Y> switchMap(
            @NonNull LiveData<X> source,
            @NonNull final Function<X, LiveData<Y>> switchMapFunction) {
        
         //监听 source 的变化 获取 source 的值
         //在通过 switchMapFunction 返回新LiveData  再监听此 LiveData 的值该变 set给result
        final MediatorLiveData<Y> result = new MediatorLiveData<>();
        result.addSource(source, new Observer<X>() {
            LiveData<Y> mSource;

            @Override
            public void onChanged(@Nullable X x) {
                LiveData<Y> newLiveData = switchMapFunction.apply(x);
                if (mSource == newLiveData) {
                    return;
                }
                if (mSource != null) {
                    result.removeSource(mSource);
                }
                mSource = newLiveData;
                if (mSource != null) {
                    result.addSource(mSource, new Observer<Y>() {
                        @Override
                        public void onChanged(@Nullable Y y) {
                            result.setValue(y);
                        }
                    });
                }
            }
        });
        return result;
    }

   
    @MainThread
    @NonNull
    public static <X> LiveData<X> distinctUntilChanged(@NonNull LiveData<X> source) {
        //每次不同的值该变 才能触发 outputLiveData onChanged
        final MediatorLiveData<X> outputLiveData = new MediatorLiveData<>();
        outputLiveData.addSource(source, new Observer<X>() {
            boolean mFirstTime = true;
            @Override
            public void onChanged(X currentValue) {
                final X previousValue = outputLiveData.getValue();
                if (mFirstTime
                        || (previousValue == null && currentValue != null)
                        || (previousValue != null && !previousValue.equals(currentValue))) {
                    mFirstTime = false;
                    outputLiveData.setValue(currentValue);
                }
            }
        });
        return outputLiveData;
    }
}

Transformations用例介绍 参考:Transformations

class UserViewModel extends AndroidViewModel {
      //map
     LiveData<User> userLiveData = ...;
     //返回一个新的LiveData
     LiveData<String> userFullNameLiveData =
          Transformations.map(
                  userLiveData,
                  user -> user.firstName + user.lastName);
      });  
       
     
    //switchMap
    MutableLiveData<String> nameQueryLiveData = ...

    LiveData<List<String>> getUsersWithNameLiveData() {
        return Transformations.switchMap(
            nameQueryLiveData,
                name -> myDataSource.getUsersWithNameLiveData(name));
    }

    void setNameQuery(String name) {
        this.nameQueryLiveData.setValue(name);
    }
}

LiveData事件分发实现原理分析

LiveData构造方法

public abstract class LiveData<T> {
    //观察者集合
    private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
        new SafeIterableMap<>();
    //事件改变计数器
    static final int START_VERSION = -1;
    static final Object NOT_SET = new Object();

    int mActiveCount = 0;
    // volatile 关键字
    private volatile Object mData;
    private int mVersion;

    volatile Object mPendingData = NOT_SET;
   
    public LiveData(T value) {
          mData = value;
          mVersion = START_VERSION + 1;//事件计数器 加1
    }
   
   public LiveData() {
       mData = NOT_SET;
       mVersion = START_VERSION;
    }
}

观察者注册
observe 注册时,可以主动跟宿主生命周期绑定,不用反注册(当目标生命周期处于死亡状态会调用解注册函数)

@MainThread //主线程限制
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    //断言,这个方法只能在主线程调用,observeForever也是。
    assertMainThread("observe");
    //获取宿主的状态 死亡状态就直接退出
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // ignore
        return;
    }
    //把注册进来的observer包装成 一个具有生命周边边界的观察者
    //它能监听宿主被销毁的事件,从而主动的把自己反注册,避免内存泄漏
    //此时观察者是否处于活跃状态就等于宿主是否可见
    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;
    }
    //向Lifecycle 添加观察者
    owner.getLifecycle().addObserver(wrapper);
}

LifecycleBoundObserver

观察者对象

PS:看过Lifecycle源码的话 就会发现这种添加观察者写法的方式非常的雷同

//生命周期事件分发接口
public interface LifecycleEventObserver extends LifecycleObserver {
  
    void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event);
}

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

    LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
        super(observer);//观察者
        mOwner = owner;
    }

    @Override
    boolean shouldBeActive() {
        //使用observer方法注册的观察者都会被包装成LifecycleBoundObserver
        //观察者是否活跃就等于宿主 的状态是否大于等于STARTED,
        //如果页面当前不可见,你发送了一条消息,此时是不会被分发的,可以避免后台任务抢占资源,当页面恢复可见才会分发。
        //注意:如果使用observerForever注册的观察者,
        //会被包装成AlwaysActiveObserver,它的shouldBeActive一致返回true.即便在页面不可见也能收到数据
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    }

    @Override
    public void onStateChanged(@NonNull LifecycleOwner source,
            @NonNull Lifecycle.Event event) {
        //在这里如果监听到宿主被销毁了,则主动地把自己从livedata的观察者中移除掉
        if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
            removeObserver(mObserver);//宿主处于死亡状态时 就在map中移除观察者
            return;
        }
        //说明宿主的状态发生了变化,此时会判断宿主是否处于活跃状态
        activeStateChanged(shouldBeActive());
    }

    @Override //判断是否为同一个被观察者(activity 或者 fragment)
    boolean isAttachedTo(LifecycleOwner owner) {
        return mOwner == owner;
    }

    @Override
    void detachObserver() {//被移除map时 真正调用移除观察者的是这里
        mOwner.getLifecycle().removeObserver(this);
    }
}

ObserverWrapper

private abstract class ObserverWrapper {
    final Observer<? super T> mObserver;
    boolean mActive;
    int mLastVersion = START_VERSION;//-1  事件分出次数

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

    abstract boolean shouldBeActive();

    boolean isAttachedTo(LifecycleOwner owner) {
        return false;
    }

    void detachObserver() {
    }
    //宿主生命周期 变化调用
    void activeStateChanged(boolean newActive) {
        if (newActive == mActive) {
            return;
        }
        
        //更改观察者的状态
        mActive = newActive;
        //初次添加观察者时为0
        boolean wasInactive = LiveData.this.mActiveCount == 0;
        //如果此时有且只有一个活跃的观察者则触发onActive
        LiveData.this.mActiveCount += mActive ? 1 : -1;
        if (wasInactive && mActive) {
            //可以做一些初始化工作
            onActive();
        }
        //没有任何一个活跃的观察者则触发onInactive
        //利用这个方法被触发的时机,可以做很多事,比如资源释放等
        if (LiveData.this.mActiveCount == 0 && !mActive) {
            onInactive();
        }

        //如果此时观察者处于活跃状态,下面就开始分发数据了
        //请注意,这里传递了this = observer
        if (mActive) {
            dispatchingValue(this);
        }
    }
}

dispatchingValue

数据分发流程控制

//2个 boolean 值 类似于flag 开关 用于控制 数据分发时顺序控制
private boolean mDispatchingValue;
private boolean mDispatchInvalidated;

void dispatchingValue(@Nullable ObserverWrapper initiator) {
    if (mDispatchingValue) {//true 说明 下面的数据分发流程还没走完
        mDispatchInvalidated = true;
        return;
    }
    mDispatchingValue = true;
    do {
        mDispatchInvalidated = false;
        if (initiator != null) {
            //首次注册观察 数据同步下发到观察者
            //黏性事件的分发 解决先发数据 在注册观察者 一样能收到新数据
            considerNotify(initiator);
            initiator = null;
        } else {
            for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                //非首次注册观察 数据同步下发到观察者
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {// true 说明有新数据来了 这次数据下发已经没有意义了 
                    break; //结束循环
                }
            }
        }
    } while (mDispatchInvalidated); //接着执行 
    mDispatchingValue = false;
}

considerNotify
数据真正分发的地方,需要满足三个条件

private void considerNotify(ObserverWrapper observer) {
    //宿主不是活跃状态
    if (!observer.mActive) {
        return;
    }
    //判断宿主不是活跃状态 并且更改观察者的状态为false
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    //此处判断观察者接收消息的次数是否大于等于 发送消息的次数
    //但是observer被创建之初verison=-1 
   //如果此时LiveData已经发送过数据了。这里就不满足了,就出现黏性事件了,后注册的观察者收到了前面发送的消息。
    // mLastVersion =-1  mVersion=1 ||>1
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    //每分发一次消息,则把观察者和LiveData的version对齐,防止重复发送
    observer.mLastVersion = mVersion;
    //最后的数据传递
    observer.mObserver.onChanged((T) mData);
}

setValue / postValue
事件更新发送

//可以在子线程执行
protected void postValue(T value) {
    boolean postTask;
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        mPendingData = value;
    }
    if (!postTask) {
        return;
    }
    //底层是通过Handler.post(runnable) 扔回主线程执行
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}

//必须在主线程执行
@MainThread
protected void setValue(T value) {
    assertMainThread("setValue");
    mVersion++; 
    mData = value;
    //事件分发
    dispatchingValue(null);
}

其他观察者:AlwaysActiveObserver
不用去关心宿主生命周期状态 任何时候 都能观察到数据的改变 关键在 shouldBeActive 任何时候都返回true 不去检查宿主生命周期状态

//不用去关心宿主生命周期状态 任何时候 都能观察到数据的改变
@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
    assertMainThread("observeForever");
    AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
    //添加到观察者结合
    ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    if (existing != null && existing instanceof LiveData.LifecycleBoundObserver) {
        throw new IllegalArgumentException("Cannot add the same observer"
                + " with different lifecycles");
    }
    if (existing != null) {
        return;
    }
    wrapper.activeStateChanged(true);
}

private class AlwaysActiveObserver extends ObserverWrapper {

    AlwaysActiveObserver(Observer<? super T> observer) {
        super(observer);
    }
    @Override//始终返回true
    boolean shouldBeActive() {
        return true;
    }
}

//移除观察者
@MainThread
public void removeObserver(@NonNull final Observer<? super T> observer) {
    assertMainThread("removeObserver");
    ObserverWrapper removed = mObservers.remove(observer);
    if (removed == null) {
        return;
    }
    removed.detachObserver();//移除宿主的生命周期观察者
    removed.activeStateChanged(false); //调用onInactive()做一些资源释放工作
}
//移除这个宿主中的所有观察者
@SuppressWarnings("WeakerAccess")
@MainThread
public void removeObservers(@NonNull final LifecycleOwner owner) {
    assertMainThread("removeObservers");
    for (Map.Entry<Observer<? super T>, ObserverWrapper> entry : mObservers) {
        if (entry.getValue().isAttachedTo(owner)) {
            removeObserver(entry.getKey());
        }
    }
}

LiveData总结

  • 确保界面符合数据状态
    LiveData 遵循观察者模式。当生命周期状态发生变化时,LiveData 会通知 [Observer]对象并把最新数据派发给它。观察者可以在收到onChanged事件时更新界面,而不是在每次数据发生更改时立即更新界面。(分发过程有检查宿主(activity)生命周期的逻辑)

  • 不再需要手动处理生命周期
    只需要观察相关数据,不用手动停止或恢复观察。LiveData 会自动管理Observer的反注册,因为它能感知宿主生命周期的变化,并在宿主生命周期的onDestory自动进行反注册。因此使用LiveData做消息分发不会发生内存泄漏

  • 数据始终保持最新状态
    如果宿主的生命周期变为非活跃状态,它会在再次变为活跃状态时接收最新的数据。例如,曾经在后台的 Activity 会在返回前台后立即接收最新的数据。

  • 支持黏性事件的分发
    即先发送一条数据,后注册一个观察者,默认是能够收到之前发送的那条数据的

  • 共享资源
    可以使用单例模式拓展 LiveData,实现全局的消息分发总线。美团LiveEventBus

    1610611274752.jpg

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容