(4.1.29.1)LiveData数据驱动者

一、概述

简单地说,LiveData是一个数据持有类。它具有以下特点:

  1. 数据可以被观察者订阅;
  2. 能够感知组件(Fragment、Activity、Service)的生命周期;
  3. 当数据变化时,只有在组件出于激活状态(STARTED、RESUMED)才会通知观察者有数据更新;

文中提到的“组件”皆指实现了LifecycleOwner接口Fragment、Activity。

1.1 为什么需要LiveData

从LiveData具有的特点,我们就能联想到它能够解决我们遇到的什么问题。LiveData具有以下优点:

  • 能够保证数据和UI统一
    • 这个和LiveData采用了观察者模式有关,LiveData是被观察者,当数据有变化时会通知观察者(UI)。
    • 一个观察者只能和一个被观察者绑定,如果重复绑定会跑出异常
  • 减少内存泄漏
    • 这是因为LiveData能够感知到组件的生命周期,当组件处于DESTROYED状态时,观察者对象会被清除掉。
  • 当Activity停止时不会引起崩溃
    • 这是因为组件处于非激活状态时,不会收到LiveData中数据变化的通知。
  • 不需要额外的手动处理来响应生命周期的变化
    • 这一点同样是因为LiveData能够感知组件的生命周期,所以就完全不需要在代码中告诉LiveData组件的生命周期状态。
  • 组件和数据相关的内容能实时更新
    • 组件在前台的时候能够实时收到数据改变的通知,这是可以理解的。当组件从后台到前台来时,LiveData能够将最新的数据通知组件,这两点就保证了组件中和数据相关的内容能够实时更新。
  • 针对configuration change时,不需要额外的处理来保存数据
    • 我们知道,当你把数据存储在组件中时,当configuration change(比如语言、屏幕方向变化)时,组件会被recreate,然而系统并不能保证你的数据能够被恢复的。当我们采用LiveData保存数据时,因为数据和组件分离了。当组件被recreate,数据还是存在LiveData中,并不会被销毁。
  • 资源共享
    • 通过继承LiveData类,然后将该类定义成单例模式,在该类封装监听一些系统属性变化,然后通知LiveData的观察者,这个在继承LiveData中会看到具体的例子。

注意项:

  1. 一个Observer对象只能和一个Lifecycle对象绑定,否则将抛出异常
  2. 同个Observer对象不能同时使用observe()和observeForever()函数,否则将抛出异常
  3. LiveData存在丢值的可能性。当单线程连续传值或者多线程同时postValue时,最终可能只有最后一个值能够被保留并回调
  4. LiveData 存在仅有部分 Observer 有收到值回调的可能性。当单线程连续传值或者多线程同时传值时,假设是先后传valueA和valueB,可能只有部分Observer可以接收到valueA,然后所有Observer都接收到了valueB
  5. 新旧值判断会根据版本来,版本号根据调用时间来

二、LiveData使用

在了解LiveData定义和优点后,那它到底怎么应用呢?LiveData有几种使用方式:

  1. 使用LiveData对象
  2. 继承LiveData类

2.1 使用LiveData对象

使用LiveData对象主要有以下几个步骤:

  1. 创建保存特定数据类型的LiveData实例;
  2. 创建Observer对象,作为参数传入LiveData.observe()方法添加观察者;
    • void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer)
    • void observeForever(@NonNull Observer observer)
  3. 更新Livedata对象存储的数据;
    • void postValue(T value)
    • void setValue(T value)

2.1.1 创建LiveData实例

Android文档中建议LiveData配合ViewModel使用更加哦,其实呢,你也可以不使用ViewModel,但是一定要做到LiveData中保存的数据和组件分离,至于原因,前面我们已经提到过了。

下面是在ViewModel中创建LiveData实例的例子:

public class NameViewModel extends ViewModel{
    // Create a LiveData with a String
    private MutableLiveData<String> mCurrentName;
    // Create a LiveData with a String list
    private MutableLiveData<List<String>> mNameListData;

    public MutableLiveData<String> getCurrentName() {
        if (mCurrentName == null) {
            mCurrentName = new MutableLiveData<>();
        }
        return mCurrentName;
    }

    public MutableLiveData<List<String>> getNameList(){
        if (mNameListData == null) {
            mNameListData = new MutableLiveData<>();
        }
        return mNameListData;
    }
}

在NameViewModel中创建了两个MutableLiveData(MutableLiveData是LiveData的子类)实例,分别存储当前姓名、姓名列表;

两个实例通过NameViewModel中的getter方法得到。

2.1.2 创建Observer对象,添加观察者

public class LiveDataFragment extends Fragment {
    private static final String TAG = "LiveDataFragment";
    private NameViewModel mNameViewModel;
    @BindView(R.id.tv_name)
    TextView mTvName;

    public static LiveDataFragment getInstance(){
        return new LiveDataFragment();
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mNameViewModel = ViewModelProviders.of(this).get(NameViewModel.class);
        mNameViewModel.getCurrentName().observe(this,(String name) -> {
            mTvName.setText(name);
            Log.d(TAG, "currentName: " + name);
        }); // 订阅LiveData中当前Name数据变化,以lambda形式定义Observer
        mNameViewModel.getNameList().observe(this, (List<String> nameList) -> {
            for (String item : nameList) {
                Log.d(TAG, "name: " + item);
            }
        }); // 订阅LiveData中Name列表数据变化,以lambda形式定义Observer
    }


    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.layout_livedata, container, false);
        ButterKnife.bind(this, view);
        return view;
    }

}

在onCreate()方法中通过LiveData.observe()方法添加观察者,当数据变化时会通过回调方法通知观察者,在lambda表达式中更新当前姓名和打印姓名列表。

2.1.3 更新LiveData中的数据

在上面我们已经订阅了LiveData数据变化,现在我们看下如果LiveData数据变化时,上面的lambda表达式中是否会受到更新的通知。我们在LiveDataFragment中增加两个按钮来改变LiveData中的数据。

@OnClick({R.id.btn_change_name, R.id.btn_update_list})
void onClicked(View view){
    switch (view.getId()){
        case R.id.btn_change_name:
            mNameViewModel.getCurrentName().setValue("Jane");
            break;
        case R.id.btn_update_list:
            List<String> nameList = new ArrayList<>();
            for (int i = 0; i < 10; i++){
                nameList.add("Jane<" + i + ">");
            }
            mNameViewModel.getNameList().setValue(nameList);
            break;
    }
}

代码很简单,在两个按钮的点击事件中通过LiveData.setValue()方法来改变LiveData中保存的数据。当点击这两个按钮的时候,我们会发现在onCreate()方法中会收相应到数据改变的回调。

2.2 继承LiveData类

除了直接使用LiveDatad对象外,我们还可以通过集成LiveData类来定义适合特定需求的LiveData。

下面继承LiveData类的例子,验证下LiveData的其中一个优点——资源共享;

  • 实现
    1. MyLiveData是个继承了LiveData的单例类,在onActive()和onInactive()方法中分别注册和反注册Wifi信号强度的广播。
    2. 然后在广播接收器中更新MyLiveData对象。
  • 使用
    • 在使用的时候就可以通过MyLiveData.getInstance()方法,然后通过调用observe()方法来添加观察者对象,订阅Wifi信息强度变化。

其中有两个点,实现了有需要的时候监听,没需要的时候不监听

  • onActive(),此方法是当处于激活状态的observer个数从0到1时,该方法会被调用。
  • onInactive() ,此方法是当处于激活状态的observer个数从1变为0时,该方法会被调用。
public class MyLiveData extends LiveData<Integer> {
    private static final String TAG = "MyLiveData";

	/******************************** 单例模式 ****************************/
    private WeakReference<Context> mContextWeakReference;
    private MyLiveData(Context context){
        mContextWeakReference = new WeakReference<>(context);
    }

	private static MyLiveData sData;
    public static MyLiveData getInstance(Context context){
        if (sData == null){
            sData = new MyLiveData(context);
        }
        return sData;
    }



    @Override
    protected void onActive() {
        super.onActive();
        registerReceiver();
    }

    @Override
    protected void onInactive() {
        super.onInactive();
        unregisterReceiver();
    }

    private void registerReceiver() {
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
        mContextWeakReference.get().registerReceiver(mReceiver, intentFilter);
    }

    private void unregisterReceiver() {
        mContextWeakReference.get().unregisterReceiver(mReceiver);
    }


    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            Log.d(TAG, "action = " + action);
            if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) {
                int wifiRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
                int wifiLevel = WifiManager.calculateSignalLevel(
                        wifiRssi, 4);
                sData.setValue(wifiLevel);
            }
        }
    };
}

三、源码解析

3.1 类关系

3.1.1 Observer接口

Observer接口就是观察者,其中定义了LiveData数据变化的回调方法onChanged()

public interface Observer<T> {
    /**
     * Called when the data is changed.
     * @param t  The new data
     */
    void onChanged(@Nullable T t);
}

3.1.2 LifecycleBoundObserver感知生命周期

  • LiveData有个内部类LifecycleBoundObserver,它实现了GenericLifecycleObserver
  • GenericLifecycleObserver继承了LifecycleObserver接口。
    • 在这里可以回顾下Lifecycle组件相关的内容。
    • 当组件(Fragment、Activity)生命周期变化时会通过onStateChanged()方法回调过来。
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);
        }
    }

3.1.3 LiveData体系

MediatorLiveData继承自MutableLiveData,MutableLiveData继承自LiveData。

MediatorLiveData可以看成是多个LiveData的代理,当将多个LiveData添加到MediatorLiveData,任何一个LiveData数据发生变化时,MediatorLiveData都会收到通知

public abstract class LiveData<T>

public class MutableLiveData<T> extends LiveData<T>

public class MediatorLiveData<T> extends MutableLiveData<T>

3.2 添加观察者

在Fragment/Activity中通过LiveData.observer()添加观察者(observer()方法中的第二个参数)

LiveData提供了两种添加观察者的方法:observeForever()、observe()。

3.2.1 observeForever()

  • 通过observeForever()添加观察者,观察者会一直受到数据的变化回到,而不是在组件处于STARTED和RESUMED状态下才会收到,因为这是LifecycleOwner对象就不再是组件了,而是ALWAYS_ON
  • 另外通过该方法添加观察者后,要手动调用removeObserver()方法来停止观察者接收回调通知
@MainThread
public void observeForever(@NonNull Observer<T> observer) {
    observe(ALWAYS_ON, observer);
}

observeForever()方法体很简单,调用了observe()方法,传入的一个参数是ALWAYS_ON常量,重点看下ALWAYS_ON常量是个啥东东。

private static final LifecycleOwner ALWAYS_ON = new LifecycleOwner() {

    private LifecycleRegistry mRegistry = init();

    private LifecycleRegistry init() {
        LifecycleRegistry registry = new LifecycleRegistry(this);
        registry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
        registry.handleLifecycleEvent(Lifecycle.Event.ON_START);
        registry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
        return registry;
    }

    @Override
    public Lifecycle getLifecycle() {
        return mRegistry;
    }
};

1.ALWAYS_ON是LifecycleOwner常量,在init方法中会初始化Lifecycle的生命周期状态。一直到Reumed状态
2. 完了之后,就没有改变过Lifecycle的生命周期状态了

这也就是为什么通过observeForever()添加观察者是,当数据改变时不管组件处于什么状态都会收到回调的原因,除非手动将观察者移除

3.2.2 observe()

  1. 将LifecycleOwner对象和Observer对象封装成LifecycleBoundObserver对象。
    • 这个对象会感知生命周期变化,并触发activeStateChanged
    • 然后触发onActive()、onInactive()、dispatchingValue(this);
  2. mObservers可以理解成一个类似Map的容器,putIfAbsent()方法是判断容器中的observer(key)是否有已经和wrapper(value)关联
    • 如果已经关联则返回关联值
      • 如果关联值存在,且该 observer 对象已经绑定了其它的 LifecycleOwner 对象,抛出异常
    • 否则关联并返回wrapper。
  3. 开始观察LifecycleOwner
private SafeIterableMap<Observer<T>, ObserverWrapper> mObservers =
            new SafeIterableMap<>();
            
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // ignore
        return;
    }
    //将LifecycleOwner对象和Observer对象封装成LifecycleBoundObserver对象。
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    // mObservers可以理解成一个类似Map的容器
    //将 observer 作为 key,wrapper 作为 value 进行存储
    //当 mObservers 不包含该 key 时,调用 putIfAbsent 会返回 null
    //当 mObservers 已包含该 key 时,调用 putIfAbsent 不会存储 key-value,并会返回之前保存的 value
    LifecycleBoundObserver existing = mObservers.putIfAbsent(observer, wrapper);
    if (existing != null && existing.owner != wrapper.owner) {
    	//走到此步,说明之前 LiveData 内部已经持有了 observer 对象
    	//且该 observer 对象已经绑定了其它的 LifecycleOwner 对象
        //此时直接抛出异常
        throw new IllegalArgumentException("Cannot add the same observer"
                + " with different lifecycles");
    }
    if (existing != null) {
    	//observer 之前已经传进来过了,此处直接返回
        return;
    }
    owner.getLifecycle().addObserver(wrapper); //条件LifecycleOwner的生命周期观察者
}

3.3 组件(Fragment/Activity)生命周期发生变化时

  • LifecycleOwner对象生命周期发生变化时,会通过该回调方法通知过来。
    • 如果当前处于Lifecycle.State.DESTROYED时,会自动将观察者移除
    • 判断是否处于actived状态,并将结果作为参数传递给activeStateChanged()
      • onActive() 处于激活状态的observer个数从0到1
      • onInactive()处于激活状态的observer个数从1变为0
      • dispatchingValue(this)
  class LifecycleBoundObserver implements GenericLifecycleObserver {
    public final LifecycleOwner owner;
    public final Observer<T> observer;//外部传进来的对 LiveData 进行数据监听的 Observer
    public boolean active;
    public int lastVersion = START_VERSION;

    LifecycleBoundObserver(LifecycleOwner owner, Observer<T> observer) {
        this.owner = owner;
        this.observer = observer;
    }

    @Override
    public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
        // LifecycleOwner对象生命周期发生变化时,会通过该回调方法通知过来。
        // 如果当前处于Lifecycle.State.DESTROYED时,会自动将观察者移除。
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            removeObserver(observer);
            return;
        }
        // 判断是否处于actived状态,并将结果作为参数传递给activeStateChanged()
        activeStateChanged(isActiveState(owner.getLifecycle().getCurrentState()));
    }

    void activeStateChanged(boolean newActive) {
        if (newActive == active) { //新状态和之前状态相同,不处理
            return;
        }
        active = newActive;
        boolean wasInactive = LiveData.this.mActiveCount == 0;
        LiveData.this.mActiveCount += active ? 1 : -1;
        if (wasInactive && active) { //处于激活状态的observer个数从0到1
            onActive();
        }
        if (LiveData.this.mActiveCount == 0 && !active) { //处于激活状态的observer个数从1变为0
            onInactive();
        }
        if (active) {
            dispatchingValue(this); 
        }
    }
}

onActive()和onInactive()都是空实现的方法,继承类可以选择去实现。

3.3.1 dispatchingValue(@Nullable LifecycleBoundObserver initiator)触发回调

我们看下dispatchingValue()方法的具体实现。

 //用于标记当前是否正处于向 mObservers 发布 value 的过程
 private boolean mDispatchingValue;
 //用于标记当前正在发布的 value 是否已经失效
 //在 value 还未向所有 Observer 发布完成的时候,新 value 已经到来,此时旧 value 就是处于失效状态
 @SuppressWarnings("FieldCanBeLocal")
  private boolean mDispatchInvalidated;

 //initiator 为 null 则说明需要遍历回调整个 mObservers
 //initiator 不为 null 则说明仅回调 initiator 本身
	@SuppressWarnings("WeakerAccess") /* synthetic access */
    void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            //如果当前正处于向 mObservers 发布 mData 的过程中(即 mDispatchingValue 为 true)
            //则将 mDispatchInvalidated 置为 true,用于标明有新值到来,正在回调的值是已经过时的了
            mDispatchInvalidated = true;
            return;
        }
        //用于标记当前正处于向 mObservers 发布 mData 的过程中
        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) {
                        //如果 mDispatchInvalidated 为 true,则中断继续遍历过程
                        //用新值来重新循环一遍
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }

@SuppressWarnings("unchecked")
    private void considerNotify(ObserverWrapper observer) {
        //如果 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.
        //此处判断主要是为了照顾 LifecycleBoundObserver
        //由于 Lifecycle 有可能状态值 State 已经切换到了非活跃状态,但 LifecycleBoundObserver 还未收到事件通知
        //所以为了避免意外情况,此处主动检查 observer 的活跃状态并判断是否需要更新其活跃状态
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        //根据 observer 本部的 value 版本号 mLastVersion 来决定是否需要向其进行回调
        //为了避免重复向某个 observer 回调值,所以此处需要判断下
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);
    }

3.4 改变LiveData数据

LiveData提供了两种改变数据的方法:setValue()和postValue()。区别是setValue()要在主线程中调用,而postValue()既可在主线程也可在子线程中调用。

我们先看setValue()方法的具体实现:

@MainThread
protected void setValue(T value) {
    assertMainThread("setValue"); //判断当前线程是否是主线程,不是主线程就抛出异常
    mVersion++;
    mData = value;
    dispatchingValue(null);
}

再看下postValue()方法的具体实现:

protected void postValue(T value) {
    boolean postTask;
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        mPendingData = value;
    }
    if (!postTask) {
        return;
    }
    // 会在主线程中执行  mPostValueRunnable中的内容。
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable); 
}

private final Runnable mPostValueRunnable = new Runnable() {
    @Override
    public void run() {
        Object newValue;
        synchronized (mDataLock) {
            newValue = mPendingData;
            mPendingData = NOT_SET;
        }
        // 在主线程中调用setValue()方法
        setValue((T) newValue); 
    }
};

postValue()方法通过ArchTaskExecutor实现在主线程中执行mPostValueRunnable对象中的内容,而在mPostValueRunnable中最终会调用setValue()方法来实现改变LiveData存储的数据

参考文献

  • LiveData还不熟悉?看完原理立马释怀!
  • LiveData

你可能感兴趣的:((4.1.29.1)LiveData数据驱动者)