本文共 8089 字,大约阅读时间需要 26 分钟。
近期的业务代码中使用到了LiveData,研究了一下发现很好用,因此总结整理出了此篇学习笔记。希望各位多批评指正。
简单地来说,LiveData就是一个持有数据的类。
需要注意的是:(1)当观察者从后台到前台来时,LiveData能够将最新的数据通知给观察者,保证数据实时更新;(2)组件在ReCreate时,会经历N个生命周期方法,但是ViewModel还是之前的对象。因此LiveData常结合VM使用。
LiveData的使用有两种方式,结合ViewModel使用LiveData对象或者直接继承LiveData类。
以一个简单的例子展示,使用LiveData子类MutableLiveData,维护一个String类型的数据:
public class MyViewModel extends ViewModel{ // Create a LiveData with a String private MutableLiveDatamData; public MutableLiveData getCurrentData() { if (mData == null) { mData = new MutableLiveData<>(); } return mData; }}
接着,创建并注册观察者:
public class LiveDataFragment extends Fragment{ private MyViewModel mViewModel; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); //这里执行注册 mViewModel = ViewModelProviders.of(this).get(MyViewModel.class); mViewModel.getCurrentData().observe(this, new Observer() { @Override public void onChanged(@Nullable String data) { //LiveData数据变化后的回调 } }); }}
使用setValue更新LiveData中的数据
mViewModel.getCurrentData().setValue("yanxuan");
除了直接使用LiveData对象,还可以通过直接继承LiveData类来定义适合特定需求的LiveData。下面的例子使用LiveData简单地实现一个资源共享的需求。
public class MyLiveData extends LiveData{ private static MyLiveData mData; private WeakReference mContext; public static MyLiveData getInstance(Context context){ if (mData == null){ mData = new MyLiveData(context); } return mData; } private MyLiveData(Context context){ mContext = new WeakReference<>(context); } @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); mContext.get().registerReceiver(mReceiver, intentFilter); } private void unregisterReceiver() { mContext.get().unregisterReceiver(mReceiver); } private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { mData.setValue(getWifiLevel(intent)); } };}
在onActive()和onInactive()方法中分别注册和反注册Wifi信号强度的广播,并且在广播接收器中更新数据。 在使用的时候就可以通过MyLiveData.getInstance().observe()方法来添加观察者对象和observer。
主要从以下三个方面进行分析:
public void observe(@NonNull LifecycleOwner owner, @NonNull Observerobserver) { if (owner.getLifecycle().getCurrentState() == DESTROYED) { // ignore return; } //将LifecycleOwner对象和Observer对象封装成LifecycleBoundObserver对象 LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer); //mObservers(一个类似Map的容器)的putIfAbsent()方法 //用于判断容器中的observer(key)是否有已经和wrapper(value)关联 //如果已关联则返回关联值,否则关联之后并返回wrapper。 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);}
首先将LifecycleOwner对象和Observer对象封装成LifecycleBoundObserver对象,LifecycleBoundObserver是一个内部类,它继承自ObserverWrapper,并实现了GenericLifecycleObserver,而GenericLifecycleObserver继承了LifecycleObserver接口。当组件生命周期变化时会通过onStateChanged()方法回调过来。
通过上面的分析,观察者就是LifecycleBoundObserver对象,下面我们看一下LifecycleBoundObserver具体实现。
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver { @NonNull final LifecycleOwner mOwner; LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observerobserver) { 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) { //DESTROYED状态下移除观察者 //该行代码会间接调用下面的detachObserver()方法 removeObserver(mObserver); return; } //判断是否处于actived状态,并将结果作为参数传递给activeStateChanged() activeStateChanged(shouldBeActive()); } @Override boolean isAttachedTo(LifecycleOwner owner) { return mOwner == owner; } @Override void detachObserver() { mOwner.getLifecycle().removeObserver(this); }}
当组件(Fragment/Activity)生命周期发生变化时,onStateChanged()方法会被调用。如果当前处于Lifecycle.State.DESTROYED时,会自动将观察者移除;若当前处于ACTIVE状态,则继续调用activeStateChanged()方法,该方法位于父类ObserverWrapper中:
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); //数据通知 }}
可以看到,若新状态和之前状态相同,则不进行不处理。 并且,当处于激活状态的observer个数从0到1时,调用onActive(); 当处于激活状态的observer个数从1到0时,调用onInactive()。
以上的onActive()和onInactive()都是空实现的方法,继承类可以选择去实现
最后调用的是dispatchingValue()进行数据变化时的消息通知,最终的回调代码如下。mObserver即为调用observe()注册时传入的Observer对象。
observer.mObserver.onChanged((T) mData);
LiveData提供了两种改变数据的方法:在主线程调用的setValue()方法,以及在子线程中调用的postValue()方法。我们先看setValue()方法的具体实现:
protected void setValue(T value) { assertMainThread("setValue"); mVersion++; mData = value; dispatchingValue(null);}
首先判断当前线程是否是主线程,不是就会抛出异常。将数据赋值给mData后,调用了dispatchingValue()进行数据通知,该方法3.2中已经讨论过了。
protected void postValue(T value) { boolean postTask; synchronized (mDataLock) { postTask = mPendingData == NOT_SET; //数据赋值给mPendingData,等待在主线程中使用 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; } //最终调用setValue() setValue((T) newValue); }};
在postValue()方法中,通过ArchTaskExecutor实现在主线程中执行mPostValueRunnable中的内容,而在mPostValueRunnable的run()中最终会调用setValue()方法来实现改变LiveData中的数据。
结合ViewModel的生命周期特点,LiveData很适合用于Fragment与Fragment之间的通信、Fragment与Activity之间的通信等。
需要注意的是,数据发送方和接收方传给方法ViewModelProviders.of()的对象必须一致,最终得到的才是同一个ViewModel对象。转载请注明出处:https://blog.csdn.net/SEU_Calvin/article/details/82256693
1. 当Fragment被detach再attach回来之后,如果你每次在onCreateView都会add新的observer实例,会导致添加多个observer。
这是因为Fragment在onDestroy才通知LiveData移除observers,若每次onCreateView都会add新的observer实例,这样就会导致数据更新时,LiveData会同时通知多个Observer,界面就会快速刷新多次。解决方式是当你在onCreateView方法中添加LiveData.observer(LifecycleOwner owner, Observer<T> observer)
时,第一个参数使用Fragment.getViewLifecycleOwner()
方法返回值。
2. 如果你使用了Fragment.getViewLifecycleOwner()作为参数, 但是同时
自己又在onCreateView中处理了Fragmeng缓存, 导致不管如何切换fragment, 仅第一次才去add observer实例,这样的写法显然会导致attach回来之后observer失效。解决方法之一是改回Frament作为参数,或者每次onCreateView都保证去add一次observer实例。