转载自: Android 架构组件(二)——LiveData
上一篇文章讲到了Android架构组件之一Lifecycle组件(Android 架构组件(一): Lifecycle),现在我们再来看看另一个成员LiveData。
定义
简单地说,LiveData是一个数据持有类。它具有以下特点:
-
数据可以被观察者订阅;
-
能够感知组件(Fragment、Activity、Service)的生命周期;
-
只有在组件出于激活状态(STARTED、RESUMED)才会通知观察者有数据更新;
PS: 文中提到的“组件”皆指实现了LifecycleOwner接口Fragment、Activity。
为什么需要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中会看到具体的例子。
LiveData使用
在了解LiveData定义和优点后,那它到底怎么应用呢?LiveData有几种使用方式:
- 使用LiveData对象
- 继承LiveData类
使用LiveData对象
使用LiveData对象主要有以下几个步骤:
- 创建保存特定数据类型的LiveData实例;
- 创建Observer对象,作为参数传入LiveData.observe()方法添加观察者;
- 更新Livedata对象存储的数据;
创建LiveData实例
Android文档中建议LiveData配合ViewModel使用更加哦,其实呢,你也可以不使用ViewModel,但是一定要做到LiveData中保存的数据和组件分离,至于原因,前面我们已经提到过了。下面是在ViewModel中创建LiveData实例的例子:
/** * Created by shymanzhu on 2017/12/20. */ 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方法得到。
创建Observer对象,添加观察者
/** * Created by shymanzhu on 2017/12/19. */ 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表达式中更新当前姓名和打印姓名列表。
更新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()方法中会收相应到数据改变的回调。
继承LiveData类
除了直接使用LiveDatad对象外,我们还可以通过集成LiveData类来定义适合特定需求的LiveData。下面继承LiveData类的例子,验证下LiveData的其中一个优点——资源共享。
/** * Created by shymanzhu on 2017/12/19. */ public class MyLiveData extends LiveData<Integer> { private static final String TAG = "MyLiveData"; private static MyLiveData sData; private WeakReference<Context> mContextWeakReference; public static MyLiveData getInstance(Context context){ if (sData == null){ sData = new MyLiveData(context); } return sData; } private MyLiveData(Context context){ mContextWeakReference = 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); 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); } } }; } |
MyLiveData是个继承了LiveData的单例类,在onActive()和onInactive()方法中分别注册和反注册Wifi信号强度的广播。然后在广播接收器中更新MyLiveData对象。在使用的时候就可以通过MyLiveData.getInstance()方法,然后通过调用observe()方法来添加观察者对象,订阅Wifi信息强度变化。
- onActive(),此方法是当处于激活状态的observer个数从0到1时,该方法会被调用。
- onInactive() ,此方法是当处于激活状态的observer个数从1变为0时,该方法会被调用。
LiveDta原理
对于某个组件的原理解析,个人现在比较习惯于从类图、时序、源码几个方面着手分析。下面的内容也是从这几点依次展开的
类关系图
LiveData的类关系图相对比较简单,从上面的类图我们就能看到。和LiveData组件相关的类和接口有:LiveData类、Observer接口、GenericLifecycleObserver接口。LiveData类是个抽象类,但是它没有抽象方法,抽象类有个特点是:不能在抽象类中实例化自己。为什么LiveData会被定义成abstract而又没有抽象方法呢,这个…我也不知道,看了下LiveData的提交记录,是在将hasObservers()替换getObserverCount()方法时将LiveData改成了abstract,在此之前它是被定义为public,可以翻墙的可以看下这里的修改记录
-
MediatorLiveData继承自MutableLiveData,MutableLiveData继承自LiveData。MediatorLiveData可以看成是多个LiveData的代理,当将多个LiveData添加到MediatorLiveData,任何一个LiveData数据发生变化时,MediatorLiveData都会收到通知。
-
LiveData有个内部类LifecycleBoundObserver,它实现了GenericLifecycleObserver,而GenericLifecycleObserver继承了LifecycleObserver接口。在这里可以回顾下Lifecycle组件相关的内容。当组件(Fragment、Activity)生命周期变化时会通过onStateChanged()方法回调过来。
-
Observer接口就是观察者,其中定义了LiveData数据变化的回调方法onChanged()。
时序图
LiveData主要涉及到的时序有三个:
- 在Fragment/Activity中通过LiveData.observer()添加观察者(observer()方法中的第二个参数)。
- 根据Fragment/Activity生命周期发生变化时,移除观察者或者通知观察者更新数据。
- 当调用LiveData的setValue()、postValue()方法后,通知观察者更新数据。
源码解析
根据LiveData主要涉及到的三个时序的内容,我们通过源码看下它具体的实现。
添加观察者
LiveData提供了两种添加观察者的方法:observeForever()、observe()。
- observeForever()
@MainThread public void observeForever(@NonNull Observer<T> observer) { observe(ALWAYS_ON, observer); } |
从方法的命名,我们也能对它的功能略知一二,通过observeForever()添加观察者,观察者会一直受到数据的变化回到,而不是在组件处于STARTED和RESUMED状态下才会收到,因为这是LifecycleOwner对象就不再是组件了,而是ALWAYS_ON;另外通过该方法添加观察者后,要手动调用removeObserver()方法来停止观察者接收回调通知。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; } }; |
ALWAYS_ON是LifecycleOwner常量,在init方法中会初始化Lifecycle的生命周期状态,完了之后,就没有改变过Lifecycle的生命周期状态了,这也就是为什么通过observeForever()添加观察者是,当数据改变时不管组件处于什么状态都会收到回调的原因,除非手动将观察者移除。
- observe()
@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的容器,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对象,下面我们看下LifecycleBoundObserver具体实现。
class LifecycleBoundObserver implements GenericLifecycleObserver { public final LifecycleOwner owner; public final Observer<T> 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); } } } |
通过observe()方法添加观察者时,当组件(Fragment/Activity)生命周期发生变化时,onStateChanged()方法会被调用。如果通过observeForever()方法添加观察者时,只有在常量ALWAYS_ON初始化的时候,onStateChanged()方法会被调用三次(CREATED、STARTED、RESUMED),后面就不会收到DESTROYED的状态,这也就是为什么要通过removeObserver()方法手动移除观察者的原因。
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<Map.Entry<Observer<T>, 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; } // 会在主线程中执行 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还有更多的使用方法,具体的内容只有在你使用到的时候再去研究吧,我先抛砖引玉,剩下的就看你们的啦……