网站建设资讯

NEWS

网站建设资讯

LiveData源码分析

前言

创新互联长期为成百上千家客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为拜泉企业提供专业的成都网站建设、做网站,拜泉网站改版等技术服务。拥有10余年丰富建站经验和众多成功案例,为您定制开发。

最近的项目重构中加入LiveData框架,并且小码的T-MVVM也是用了LiveData框架,好不好用你试试就知道(小码口头禅),对于LiveData使用的时候并未做太多的理解,于是乎翻了翻LiveData源代码,在此做下笔记,

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

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

LiveData能为我们做什么

  • 能够保证数据和UI统一,LiveData采用了观察者模式,LiveData是被观察者,当数据有变化时会通知UI。
    • 减少内存泄漏,LiveData能够感知到组件的生命周期,当组件处于DESTROYED状态时,观察者对象会被清除,当Activity停止时不会导致Crash,因为组件处于非激活状态时,不会收到LiveData中数据变化的通知。
    • 不需要额外的手动处理来响应生命周期的变化,因为LiveData能够感知组件的生命周期,所以就完全不需要在代码中告诉LiveData组件的生命周期状态。
    • 组件和数据相关的内容能实时更新,组件在前台的时候能够实时收到数据改变的通知,当组件从后台到前台来时,LiveData能够将最新的数据通知组件,因此保证了组件中和数据相关的内容能够实时更新。
      若果横竖屏切换(configuration change)时,不需要额外的处理来保存数据,当屏幕方向变化时,组件会被recreate,然而系统并不能保证你的数据能够被恢复的。当我们采用LiveData保存数据时,因为数据和组件分离了。当组件被recreate,数据还是存在LiveData中,并不会被销毁。
    • 资源共享.

接下来先从使用玩起,

  • 使用LiveData对象,
  • 继承LiveData类,如MutableLiveData,
    发起数据通知2种方式:postValue和setValue:

             private MutableLiveData mData=new MutableLiveData();
                mBookData.postValue("Hello LiveData");
                // mBookData.setValue("Hello LiveData");

此处postValue和setValue的区别,下文会提,
注册观察者并监听数据变化:

 mData.observe(this, new Observer() {
        @Override
        public void onChanged(@Nullable String str) {
          Toast.makeText(this, str, Toast.LENGTH_SHORT).show();
        }
    });

使用非常简单,仅此而已
通过observe方法注册观察者,哪咋们就看看observe里面具体干了什么,源代码165行走起,

   //注册观察
 @MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer 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 ,首先判断LifecycleOwner当前的生命周期是否为Destroyed,如果是则直接 return;如果不等于Destroyed,接下来往下看, 此处new了一个内部类LifecycleBoundObserver对象并且构造方法传入了具有生命周期的LifecycleOwner和观察者,这是个什么鬼,看看他的具体方法,LifecycleBoundObserver继承自ObserverWrapper,并实现GenericLifecycleObserver,而GenericLifecycleObserver继承了LifecycleObserver接口。由此可以看出LifecycleBoundObserver类就是把Observer和生命周期关联起来,ok,那我们先看看LifecycleBoundObserver方法,源代码349行走起,

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

    LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer 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);
    }
}

此方法中,我们先看onStateChanged()方法,当生命周期变化时会回调,如果getCurrentState() == DESTROYED则removeObserver,反之则调用父类ObserverWrapper的activeStateChanged()方法,源代码382行走起,

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

    ObserverWrapper(Observer 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并且mActive为true,即观察者处于活动状态
个数从0变为1个则调用onActive(); 观察者处于活动状态
个数从1变为0时则调用onInactive()。然而onActive(),onInactive()并没有任何实现代码。好了,接下来继续往下看dispatchingValue(this);应该就是数据变化消息调度。源代码112行走起,

  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, 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)方法;源代码91行走起,

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

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

  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, ObserverWrapper> mObservers =
        new SafeIterableMap<>();

这是个什么鬼,貌似以前很少见,查阅资料发现:
SafeIterableMap有以下特性:
1;支持键值对存储,用链表实现,模拟成Map的接口
2:支持在遍历的过程中删除任意元素,不会触发ConcurrentModifiedException
3:非线程安全
感兴趣的可自行查阅,此处不再详细介绍,
最后addObserver添加注册。

下面在看看数据发起通知的逻辑,数据发起通知有2中方式:

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

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

setValue和postValue2中方式,我们先看看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");
    }
}

setValue第一行代码 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。

至此大概明白了LiveData是干嘛的 ,怎么干的,总的来说还是很好用的,于是乎就有个小小的想法,平时用Eventbus,RxBus什么的,貌似感觉LiveData也可以实现事件总线,既然有了想法,那就干呗,

/**
 * 事件总线
 *
 * @author:tqzhang on 18/9/11 17:22
 */
 public class LiveBus {

    private static volatile LiveBus instance;

    private final Map> mLiveBus;

    private LiveBus() {
       mLiveBus = new HashMap<>();
    }

    public static LiveBus getDefault() {
        if (instance == null) {
            synchronized (LiveBus.class) {
               if (instance == null) {
                   instance = new LiveBus();
                }
            }
        }
       return instance;
   }

    /**
     *
     * subscriber 注册时间 key
     */
   public  MutableLiveData subscribe(Object subscriber, Class tMutableLiveData) {
      checkNotNull(subscriber);
      checkNotNull(tMutableLiveData);
      if (!mLiveBus.containsKey(subscriber)) {
          mLiveBus.put(subscriber, new MutableLiveData<>());
      }
      return (MutableLiveData) mLiveBus.get(subscriber);

  }
}

简单的50行代码实现类似Eventbus,RxBus的功能,小码亲测了,挺好使的。

 //发起通知
LiveBus.getDefault().subscribe("livedata",String.class).postValue("hello LiveData");

//注册观察
LiveBus.getDefault().subscribe("livedata",String.class).observe(this, new Observer() {
        @Override
        public void onChanged(@Nullable String s) {
            Toast.makeText(activity, s, Toast.LENGTH_SHORT).show();
        }
    });

网站栏目:LiveData源码分析
网页链接:http://njwzjz.com/article/jeissc.html