Android架构组件—LiveData

概述

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

  • 数据可以被观察者订阅;

  • 能够感知组件(Fragment、Activity、Service)的生命周期;

  • 只有在组件出于激活状态(STARTED、RESUMED)才会通知观察者有数据更新;

LiveData的优点

  • 没有内存泄漏:因为 Observer 被绑定到它们自己的 Lifecycle 对象上,所以,当它们的 Lifecycle 被销毁时,它们能自动的被清理。

  • 不会因为 activity 停止而崩溃:如果 Observer 的 Lifecycle 处于闲置状态(例如:activity 在后台时),它们不会收到变更事件。

  • 始终保持数据最新:如果 Lifecycle 重新启动(例如:activity 从后台返回到启动状态)将会收到最新的位置数据(除非还没有)。

  • 正确处理配置更改:如果 activity 或 fragment 由于配置更改(如:设备旋转)重新创建,将会立即收到最新的有效位置数据。

  • 资源共享:可以只保留一个 MyLocationListener 实例,只连接系统服务一次,并且能够正确的支持应用程序中的所有观察者。

  • **不再手动管理生命周期:**fragment 只是在需要的时候观察数据,不用担心被停止或者在停止之后启动观察。由于 fragment 在观察数据时提供了其 Lifecycle,所以 LiveData 会自动管理这一切。

LiveData的使用

LiveData有两种使用方式:
1. 使用LiveData对象
2. 继承LiveData类

使用LiveData对象
使用步骤:

  1. 创建保存特定数据类型的LiveData实例;
  2. 创建Observer对象,作为参数传入LiveData.observe()方法添加观察者;
  3. 更新Livedata对象存储的数据;

创建LiveData实例:
Android文档中建议LiveData配合ViewModel使用更佳,下面是在ViewModel中创建LiveData实例的例子:

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

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

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

在NameViewModel中创建了两个MutableLiveData(MutableLiveData是LiveData的子类)实例,分别存储当前姓名、姓名列表;两个实例通过NameViewModel中的getter方法得到。

创建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 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(owner,observer)方法添加观察者,当数据变化时会通过回调方法通知观察者新数据。

更新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 nameList = new ArrayList<>();
            for (int i = 0; i < 10; i++){
                nameList.add("Jane<" + i + ">");
            }
            mNameViewModel.getNameList().setValue(nameList);
            break;
    }
}

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

继承LiveData类
除了直接使用LiveDatad对象外,我们还可以通过继承LiveData类来定义适合特定需求的LiveData。下面继承LiveData类的例子,验证下LiveData的其中一个优点——资源共享。

public class LocationLiveData extends LiveData {
    private static LocationLiveData sInstance;
    private LocationManager locationManager;

    @MainThread
    public static LocationLiveData get(Context context) {
        if (sInstance == null) {
            sInstance = new LocationLiveData(context.getApplicationContext());
        }
        return sInstance;
    }

    private SimpleLocationListener listener = new SimpleLocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            setValue(location);
        }
    };

    private LocationLiveData(Context context) {
        locationManager = (LocationManager) context.getSystemService(
                Context.LOCATION_SERVICE);
    }

    @Override
    protected void onActive() {
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener);
    }

    @Override
    protected void onInactive() {
        locationManager.removeUpdates(listener);
    }
}

LocationLiveData是个继承了LiveData的单例类,在onActive()和onInactive()方法中分别注册和注销Wifi定位服务。使用的时候可以通过LocationLiveData.getInstance()方法,然后通过调用observe()方法来添加观察者对象。

  • onActive():当LiveData拥有一个处在激活状态的观察者时会调用这个方法。
  • onInactive() :当LiveData并不拥有任何处在激活状态时这个方法被调用。
  • setValue():调用该方法更新LiveData实例的值,并通知处在激活状态的观察者该变化

可以这样使用新的LocationLiveData:

public class MyFragment extends LifecycleFragment {
    public void onActivityCreated (Bundle savedInstanceState) {
        LiveData myLocationListener = ...;
        Util.checkUserStatus(result -> {
            if (result) {
                myLocationListener.observer(this, location -> {
                    // 更新 UI
                });
            }
        });
    }
}

注意到addObserver()方法传递的第一个参数是LifecycleOwner,这表示观察者必然绑定至Lifecycle,这意味着:

  • 如果Lifecycle并不处在激活状态,即使值发生变化,观察者也不会被响应
  • 如果Lifecycle被销毁,观察者会被自动清除

可能会有多个Fragment和多个Activity观察我们的MyLocationListener实例,只需要我们的LocationLiveData使用单例,并且组件处在激活状态,我们的LiveData可以优雅地进行管理。

LiveData的转换

有些时候,你可能想要在分发LiveData至观察者之前做一些变化,或者需要基于当前值返回另一个LiveData实例。

Lifecycle包提供了一个Transformations类,包含这些操作的辅助方法。

Transformations.map()

LiveData userLiveData = ...;
LiveData userName = Transformations.map(userLiveData, user -> {
    user.name + " " + user.lastName
});

Transformations.switchMap()
和map()相似,传递至switchMap()的函数必须返回一个Lifecycle。

private LiveData getUser(String id) {
  ...;
}

LiveData userId = ...;LiveData user = Transformations.switchMap(userId, id -> getUser(id) );

使用这些转化允许通过链继续观察Lifecycle信息,例如这些信息只有当一个观察者观察返回LiveData的时才进行计算。这种惰性计算的特性允许在转化过程中隐式地传递生命周期,而不需要添加额外的调用或依赖。

当你在ViewModel里需要一个Lifecycle时,一个转化可能是一种解决方案。

例如,假设我们有一个UI界面,用户输入地址并接收地址的邮政编码。UI界面原始的ViewModel是这样的:

class MyViewModel extends ViewModel {
    private final PostalCodeRepository repository;
    public MyViewModel(PostalCodeRepository repository) {
       this.repository = repository;
    }

    private LiveData getPostalCode(String address) {
       // 不要这样做!
       return repository.getPostCode(address);
    }
}

实现如上,UI可能需要从之前的LiveData反注销并在每次调用getPostalCode()新的实例时重新注册。此外,如果UI是重新创建的,它出发了另一个调用repository.getPostCode(),而不是之前的结果。

作为上述方法的替换,你可以将邮政编码信息作为地址信息输入的转换:

class MyViewModel extends ViewModel {
    private final PostalCodeRepository repository;
    private final MutableLiveData addressInput = new MutableLiveData();
    public final LiveData postalCode =
            Transformations.switchMap(addressInput, (address) -> {
                return repository.getPostCode(address);
             });

  public MyViewModel(PostalCodeRepository repository) {
      this.repository = repository
  }

  private void setInput(String address) {
      addressInput.setValue(address);
  }
}

注意到我们将postalCode设为public final,因为它永远不会改变。它被定义为addressInput的转化,因此当addressInput变化的时候,如果有一个激活的观察者,repository.getPostCode()会被调用。如果没有激活的观察者,则不会有任何计算发生,直到添加了一个观察者。

这种机制允许下层的应用创建LiveData对象,在需要的时候才计算。ViewModel可以轻易地获取它们并在上层定义转化规则。

创建新的转换

在应用程序中可能会用到十几种不同的特定转换,但是默认是不提供的。可以使用 MediatorLiveData实现自己的转换,MediatorLiveData是为了用来正确的监听其它LiveData实例并处理它们发出的事件而特别创建的。MediatorLiveData需要特别注意正确的向源 LiveData 传递其处于活动/闲置状态。有关详细信息,请参阅 Transformations 类。

LiveData原理

借用Android架构组件(二)——LiveData的类关系图:

从上面的类图我们就能看到。和LiveData组件相关的类和接口有:LiveData类、Observer接口、GenericLifecycleObserver接口。LiveData类是个抽象类,但是它没有抽象方法,抽象类有个特点是:不能在抽象类中实例化自己。

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

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

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

借用Android架构组件(二)——LiveData的时序图:

LiveData主要涉及到的时序有三个:

  • 在Fragment/Activity中通过LiveData.observer()添加观察者(observer()方法中的第二个参数)。
  • 根据Fragment/Activity生命周期发生变化时,移除观察者或者通知观察者更新数据。
  • 当调用LiveData的setValue()、postValue()方法后,通知观察者更新数据。

源码解析

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

  • observeForever()
 @MainThread
    public void observeForever(@NonNull Observer observer) {
        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);
    }

通过observeForever()添加观察者,观察者会一直受到数据的变化,而不是在组件处于STARTED和RESUMED状态下才会收到。另外通过该方法添加观察者后,要手动调用removeObserver()方法来停止观察者接收回调通知。

private class AlwaysActiveObserver extends ObserverWrapper {

        AlwaysActiveObserver(Observer observer) {
            super(observer);
        }

        @Override
        boolean shouldBeActive() {
            return true;
        }
    }

重写shouldBeActive()一直返回true

// 所以一直不会进入这个方法,每次都会往下调用observer的change方法
if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
 }
  • observe()
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // ignore
        return;
    }
    //将LifecycleOwner对象和Observer对象封装成LifecycleBoundObserver对象。
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    // mObservers可以理解成一个类似Map的容器,putIfAbsent()方法是判断容器中的observer(key)
    // 是否有已经和wrapper(value)关联,如果已经关联则返回关联值,否则关联并返回wrapper。
    LifecycleBoundObserver existing = mObservers.putIfAbsent(observer, wrapper);
    if (existing != null && existing.owner != wrapper.owner) {
        throw new IllegalArgumentException("Cannot add the same observer"
                + " with different lifecycles");
    }
    if (existing != null) {
        return;
    }
    owner.getLifecycle().addObserver(wrapper); //条件LifecycleOwner的生命周期观察者
}

该方法比较简单,主要逻辑都在注释中。

组件(Fragment/Activity)生命周期发生变化
 在LiveData.observe()方法中添加了组件(实现了LifecycleOwner接口的Fragment和Activity)生命周期观察者。而这个观察者就是LifecycleBoundObserver对象:

class LifecycleBoundObserver implements GenericLifecycleObserver {
    public final LifecycleOwner owner;
    public final Observer observer;
    public boolean active;
    public int lastVersion = START_VERSION;

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

通过observe()方法添加观察者,当组件(Fragment/Activity)生命周期发生变化时,onStateChanged()方法会被调用。
onActive()和onInactive()都是空实现的方法,继承类可以选择去实现。

dispatchingValue()方法:

private void dispatchingValue(@Nullable LifecycleBoundObserver initiator) {
    if (mDispatchingValue) {
        mDispatchInvalidated = true;
        return;
    }
    mDispatchingValue = true;
    do {
        mDispatchInvalidated = false;
        if (initiator != null) {  // initiator不为空,考虑通知回调
            considerNotify(initiator);
            initiator = null;
        } else { // initiator为空,考虑通知mObservers容器中对象回调
            for (Iterator, LifecycleBoundObserver>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
    } while (mDispatchInvalidated);
    mDispatchingValue = false;
}

private void considerNotify(LifecycleBoundObserver observer) {
    if (!observer.active) {
        return;
    }
    if (!isActiveState(observer.owner.getLifecycle().getCurrentState())) {
        observer.activeStateChanged(false);
        return;
    }
    if (observer.lastVersion >= mVersion) {
        return;
    }
    observer.lastVersion = mVersion;
    // 最终回调的地方,也就是调用observe()或者observeForever()是传入的Observer对象。
    observer.observer.onChanged((T) mData);
}

改变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;
        }
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }

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

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

你可能感兴趣的:(框架,Android)