2.1.3.Architecture components_LiveData
Posted muouren
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2.1.3.Architecture components_LiveData相关的知识,希望对你有一定的参考价值。
参考
https://developer.android.com/topic/libraries/architecture/livedata
https://www.jianshu.com/p/55f94c1c5e0e
LiveData
LiveData是可观察的数据持有者类。 与常规的可观察对象不同,LiveData具有生命周期感知功能,这意味着它尊重其他应用程序组件(例如Activity,fragment或service)的生命周期。 这种意识确保LiveData仅更新处于活动生命周期状态的应用程序组件观察者。
如果LiveData的生命周期处于STARTED或RESUMED状态,则它认为由Observer类表示的观察者处于活动状态。 LiveData仅将有关更新的信息通知活动的观察者。 注册为观看LiveData对象的非活动观察者不会收到有关更改的通知。
您可以注册一个与实现LifecycleOwner接口的对象配对的observer ,也就是传递一个LifecycleOwner,一个Observer。 此关系允许 当对应的Lifecycle对象的状态更改为DESTROYED时,移除观察者。 这对于Activity和Fragment特别有用,因为它们可以安全地观察LiveData对象,而不必担心泄漏-Activity和Fragment的生命周期DESTROYED后,它们将立即取消订阅。
LiveData的使用
l 创建LiveData实例来保存某种类型的数据。 这通常是在ViewModel类中完成的。
l 创建一个定义onChanged(T)方法的Observer对象,该方法控制LiveData对象持有的数据更改时。 通常,您可以在UI控制器中创建一个Observer对象,例如Fragment或Activity。
l 使用observe()方法将Observer对象附加到LiveData对象。 observe()方法采用LifecycleOwner对象。 这会将Observer对象订阅到LiveData对象,以便将更改通知给它。 通常,您将Observer对象附加在UI控制器中,例如Fragment或Activity。
l 您可以使用observeForever(Observer)方法在没有关联LifecycleOwner对象的情况下注册观察者。 在这种情况下,观察者被视为始终处于活动状态,因此始终会收到有关修改的通知。 您可以通过调用removeObserver(Observer)方法来删除这些观察者。
更新存储在LiveData对象中的值时,只要attached 的LifecycleOwner处于活动状态,它就会触发所有注册的观察者。
LiveData允许UI控制器观察者订阅更新。 当LiveData对象保存的数据更改时,UI会自动更新以响应。
创建LiveData对象
LiveData是可与任何数据一起使用的包装器,包括实现集合的对象(例如List)。 LiveData对象通常存储在ViewModel对象中,并可以通过getter方法进行访问
public class NameViewModel extends ViewModel { // Create a LiveData with a String private MutableLiveData<String> currentName; public MutableLiveData<String> getCurrentName() { if (currentName == null) { currentName = new MutableLiveData<String>(); } return currentName; } // Rest of the ViewModel... }
注意:出于以下原因,请确保将更新UI的LiveData对象(而不是Activity或Fragment)存储在ViewModel对象中:
l 避免activities和fragment过于膨胀。 现在,这些UI控制器负责显示数据,而不负责保持数据状态。
l 使LiveData实例与特定Activity或Fragment实例脱钩,并允许LiveData对象在配置更改后继续存在。
Observe LiveData objects
一般会在onCreate中开始观测LiveData。
确保活动或片段具有可在活动后立即显示的数据。 一旦应用程序组件处于“开始”状态,它就会从其正在观察的LiveData对象中接收最新值。 仅当已设置要观察的LiveData对象时,才会发生这种情况。
通常,LiveData仅在数据更改时才将更新传递给active的观察者。 此行为的一个例外是,当观察者从 非活动状态 更改为 活动状态 时,他们也会收到更新。 此外,如果观察者第二次从非活动状态更改为活动状态,则仅当值自上次变为活动状态以来已更改时,它才接收更新。
public class NameActivity extends AppCompatActivity { private NameViewModel model; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Other code to setup the activity... // Get the ViewModel. model = ViewModelProviders.of(this).get(NameViewModel.class); // Create the observer which updates the UI. final Observer<String> nameObserver = new Observer<String>() { @Override public void onChanged(@Nullable final String newName) { // Update the UI, in this case, a TextView. nameTextView.setText(newName); } }; // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer. model.getCurrentName().observe(this, nameObserver); } }
在使用作为参数传递的nameObserver调用observe()之后,会立即调用onChanged(),以提供存储在mCurrentName中的最新值。 如果LiveData对象尚未在mCurrentName中设置值,则不会调用onChanged()。
Update LiveData objects
LiveData 是个abstract类,是没有public的setter的,可以使用其子类MutableLiveData,MutableLiveData只是把setter给public,其他的没改动。
button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { String anotherName = "John Doe"; model.getCurrentName().setValue(anotherName); } });
Extend LiveData
如果观察者的生命周期处于STARTED或RESUMED状态,则LiveData认为观察者处于活动状态。
下面的示例代码说明了如何扩展LiveData类:
public class StockLiveData extends LiveData<BigDecimal> { private StockManager stockManager; private SimplePriceListener listener = new SimplePriceListener() { @Override public void onPriceChanged(BigDecimal price) { setValue(price); } }; public StockLiveData(String symbol) { stockManager = new StockManager(symbol); } @Override protected void onActive() { stockManager.requestPriceUpdates(listener); } @Override protected void onInactive() { stockManager.removeUpdates(listener); } }
此示例中包括以下重要方法:
- l 当LiveData对象具有活动的观察者时,将调用onActive()方法。 这意味着您需要从这个方法开始观察股价更新。
- l 当LiveData对象没有任何活动的观察者时,将调用onInactive()方法。 由于没有观察者在听,因此没有理由保持与StockManager服务的连接。
- l setValue(T)方法将更新LiveData实例的值,并将有关更改通知所有活动的观察者。
You can use the StockLiveData class as follows:
public class MyFragment extends Fragment { @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); LiveData<BigDecimal> myPriceListener = ...; myPriceListener.observe(this, price -> { // Update the UI. }); } }
observe方法的第一个参数是fragment,由于fragment实现了LifecycleOwner,那么就意味着这个observer和Lifecycle对象进行绑定:
- l 如果Lifecycle对象不是处于活动状态,则即使值更改也不会调用观察者。
- l Lifecycle对象销毁后,观察者将被自动删除。
在多组件共享LiveData
LiveData对象具有生命周期感知这一事实意味着您可以在多个Activity,Fragment和Service之间共享它们。
为了使示例简单,可以按如下方式将LiveData类实现为单例:
public class StockLiveData extends LiveData<BigDecimal> { private static StockLiveData sInstance; private StockManager stockManager; private SimplePriceListener listener = new SimplePriceListener() { @Override public void onPriceChanged(BigDecimal price) { setValue(price); } }; @MainThread public static StockLiveData get(String symbol) { if (sInstance == null) { sInstance = new StockLiveData(symbol); } return sInstance; } private StockLiveData(String symbol) { stockManager = new StockManager(symbol); } @Override protected void onActive() { stockManager.requestPriceUpdates(listener); } @Override protected void onInactive() { stockManager.removeUpdates(listener); } }
And you can use it in the fragment as follows:
public class MyFragment extends Fragment { @Override public void onActivityCreated(Bundle savedInstanceState) { StockLiveData.get(symbol).observe(this, price -> { // Update the UI. }); } }
多个Fragment和Activty可以观察MyPriceListener实例。 LiveData仅在其中一个或多个可见且处于活动状态时才连接到系统服务。
Transform LiveData
可以通过Transformations把LiveData<Input>转换为另一个类型的LiveData<Output>,Transformations内部其实是使用的MediatorLiveData实现这一功能。
主要有两种转换方法:
其中x表示原类型,y表示目标类型。
map
@MainThread @NonNull public static <X, Y> LiveData<Y> map(@NonNull LiveData<X> source, @NonNull final Function<X, Y> mapFunction)
LiveData<User> userLiveData = ...; LiveData<String> userName = Transformations.map(userLiveData, user -> { user.name + " " + user.lastName });
switchMap
@MainThread @NonNull public static <X, Y> LiveData<Y> switchMap(@NonNull LiveData<X> source, @NonNull final Function<X, LiveData<Y>> switchMapFunction)
private LiveData<User> getUser(String id) { ...; } LiveData<String> userId = ...; LiveData<User> user = Transformations.switchMap(userId, id -> getUser(id) );
如果您认为需要在ViewModel对象中使用Lifecycle对象,则transformation可能是一个更好的解决方案。
例如,假设您有一个UI组件,该组件接受一个地址并返回该地址的邮政编码。 您可以为此组件实现朴素的ViewModel,如以下示例代码所示:
class MyViewModel extends ViewModel { private final PostalCodeRepository repository; public MyViewModel(PostalCodeRepository repository) { this.repository = repository; } private LiveData<String> getPostalCode(String address) { // DON‘T DO THIS return repository.getPostCode(address); } }
然后,UI组件每次调用getPostalCode()时都需要unregister 先前的LiveData对象并register 到新实例。 此外,如果重新创建了UI组件,则它会触发另一个对repository.getPostCode()方法的调用,而不是使用先前调用的结果。
相反,您可以将邮政编码查找实现为地址输入的转换,如以下示例所示:
class MyViewModel extends ViewModel { private final PostalCodeRepository repository; private final MutableLiveData<String> addressInput = new MutableLiveData(); public final LiveData<String> 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字段定义为addressInput的transformation 。 只要您的应用程序具有与postalCode字段关联的active观察者,当addressInput发生更改,便会重新计算并检索该字段的值。
此机制允许较低级别的应用程序创建按需延迟计算的LiveData对象。 ViewModel对象可以轻松获取对LiveData对象的引用,然后在它们之上定义转换规则。
Merge multiple LiveData sources
MediatorLiveData是LiveData的子类,允许您合并多个LiveData源。 每当任何原始LiveData源对象发生更改时,就会触发MediatorLiveData对象的观察者。
例如,如果您的UI中有一个LiveData对象,可以从本地数据库或网络更新该对象,则可以将以下源添加到MediatorLiveData对象:
l 与数据库中存储的数据关联的LiveData对象。
l 与从网络访问的数据关联的LiveData对象。
您的Activity仅需要观察MediatorLiveData对象即可从两个来源接收更新。
源码分析
LiveData
是一个abstract类,
@Nullable public T getValue() { Object data = mData; if (data != NOT_SET) { //noinspection unchecked return (T) data; } return null; } @MainThread protected void setValue(T value) { assertMainThread("setValue"); mVersion++; mData = value; dispatchingValue(null); } protected void postValue(T value) { boolean postTask; synchronized (mDataLock) { postTask = mPendingData == NOT_SET; mPendingData = value; } if (!postTask) { return; } ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable); } 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<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator = mObservers.iteratorWithAdditions(); iterator.hasNext(); ) { considerNotify(iterator.next().getValue()); if (mDispatchInvalidated) { break; } } } } while (mDispatchInvalidated); mDispatchingValue = false; } 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); } @MainThread public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) { assertMainThread("observe"); 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); } @MainThread public void observeForever(@NonNull Observer<? super T> observer) { assertMainThread("observeForever"); AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer); ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper); if (existing instanceof LiveData.LifecycleBoundObserver) { throw new IllegalArgumentException("Cannot add the same observer" + " with different lifecycles"); } if (existing != null) { return; } wrapper.activeStateChanged(true); } public boolean hasObservers() { return mObservers.size() > 0; } public boolean hasActiveObservers() { return mActiveCount > 0; }
ObserverWrapper
private abstract class ObserverWrapper { final Observer<? super T> mObserver; boolean mActive; int mLastVersion = START_VERSION; 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; } // 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); } } }
AlwaysActiveObserver
private class AlwaysActiveObserver extends ObserverWrapper { AlwaysActiveObserver(Observer<? super T> observer) { super(observer); } @Override boolean shouldBeActive() { return true; } }
LifecycleBoundObserver
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() { 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); } }
Observer
public interface Observer<T> { void onChanged(T t); }
MutableLiveData
是LiveData的子类,MutableLiveData只是把setter给public,其他的没改动
@Override public void postValue(T value) { super.postValue(value); } @Override public void setValue(T value) { super.setValue(value); }
MediatorLiveData
继承了MutableLiveData,
可以用来转换LiveData,或观察多个其他LiveData
@MainThread public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) { 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 protected void onActive() { for (Map.Entry<LiveData<?>, Source<?>> source : mSources) { source.getValue().plug(); } } @CallSuper @Override protected void onInactive() { for (Map.Entry<LiveData<?>, Source<?>> source : mSources) { source.getValue().unplug(); } }
Source
实现了Observer
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; } void plug() { mLiveData.observeForever(this); } void unplug() { mLiveData.removeObserver(this); } @Override public void onChanged(@Nullable V v) { if (mVersion != mLiveData.getVersion()) { mVersion = mLiveData.getVersion(); mObserver.onChanged(v); } } }
Transformations
是一个转换LiveData的工具类,都是借助MediatorLiveData来实现的。
@MainThread @NonNull public static <X, Y> LiveData<Y> map(@NonNull LiveData<X> source, @NonNull final Function<X, Y> mapFunction) { 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) { 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; }
Function
public interface Function<I, O> { /** * Applies this function to the given input. * * @param input the input * @return the function result. */ O apply(I input); }
把I转换成O输出
LiveData的问题
LiveData 粘性事件问题
意思就是说,LiveData在设置observe之前,对LiveData进行了数据修改,在之后进行observe,此时如果生命周期状态发生改变,livedata修改的数据会立马发送给观察者。
如果我只想在observe之后的修改才通知观察者,那么就没办法了,所以此时就需要进行一些特殊操作:可以通过反射来修改此行为。
分析
当我们observe时,
@MainThread public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) { assertMainThread("observe"); 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); }
我们的observer会被包装一层,包装类的基类是ObserverWrapper,在ObserverWrapper中有一个成员变量mLastVersion默认值为-1,
当生命周期状态发生改变后,
LifecycleBoundObserver
@Override boolean shouldBeActive() { return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED); } @Override public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) { if (mOwner.getLifecycle().getCurrentState() == DESTROYED) { removeObserver(mObserver); return; } activeStateChanged(shouldBeActive()); }
ObserverWrapper.activeStateChanged
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); } }
LiveData
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<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator = mObservers.iteratorWithAdditions(); iterator.hasNext(); ) { considerNotify(iterator.next().getValue()); if (mDispatchInvalidated) { break; } } } } while (mDispatchInvalidated); mDispatchingValue = false; } 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; observer.mObserver.onChanged((T) mData); }
由于我们的observer会被包装一层的mLastVersion为-1,显然此时执行下边的回调我们的onChagne,
经过分析后,原因以找出,那么解决方法也很简单,通过反射拿到 observer会被包装一层,修改其mLastVersion为mVersion即可。
具体实现:
public class UnPeekLiveData<T> extends MutableLiveData<T> { @Override public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) { super.observe(owner, observer); hook(observer); } private void hook(Observer<? super T> observer) { Class<LiveData> liveDataClass = LiveData.class; try { //获取field private SafeIterableMap<Observer<T>, ObserverWrapper> mObservers Field mObservers = liveDataClass.getDeclaredField("mObservers"); mObservers.setAccessible(true); //获取SafeIterableMap集合mObservers Object observers = mObservers.get(this); Class<?> observersClass = observers.getClass(); //获取SafeIterableMap的get(Object obj)方法 Method methodGet = observersClass.getDeclaredMethod("get", Object.class); methodGet.setAccessible(true); //获取到observer在集合中对应的ObserverWrapper对象 Object objectWrapperEntry = methodGet.invoke(observers, observer); Object objectWrapper = null; if (objectWrapperEntry instanceof Map.Entry) { objectWrapper = ((Map.Entry) objectWrapperEntry).getValue(); } if (objectWrapper == null) { throw new NullPointerException("ObserverWrapper can not be null"); } //获取ObserverWrapper的Class对象 LifecycleBoundObserver extends ObserverWrapper Class<?> wrapperClass = objectWrapper.getClass().getSuperclass(); //获取ObserverWrapper的field mLastVersion Field mLastVersion = wrapperClass.getDeclaredField("mLastVersion"); mLastVersion.setAccessible(true); //获取liveData的field mVersion Field mVersion = liveDataClass.getDeclaredField("mVersion"); mVersion.setAccessible(true); Object mV = mVersion.get(this); //把当前ListData的mVersion赋值给 ObserverWrapper的field mLastVersion mLastVersion.set(objectWrapper, mV); mObservers.setAccessible(false); methodGet.setAccessible(false); mLastVersion.setAccessible(false); mVersion.setAccessible(false); } catch (Exception e) { e.printStackTrace(); } } }
以上是关于2.1.3.Architecture components_LiveData的主要内容,如果未能解决你的问题,请参考以下文章
[Vue @Component] Simplify Vue Components with vue-class-component
[Vue @Component] Dynamic Vue.js Components with the component element