本文为《Android Architecture Components学习笔记》的一部分
水平有限,如有不当之处请不吝赐教
可参考:
https://developer.android.google.cn/topic/libraries/architecture/livedata#use_livedata_with_room
使用LiveData的优点:
-
确保UI与数据更新一致
LiveData遵循观察者模式。当生命周期状态改变时,LiveData作为被观察者会通知Observer对象中的UI执行更新。这样可以方便、集中的更新UI,而不需要逐个实现UI更新事件。 -
防止内存泄漏
当关联到Lifecycle对象的生命周期处于销毁状态时,被绑定到观察者的对象可自行清理。 -
Activity停止后不会导致崩溃
如果观察者生命周期处于非活动状态,例如在回退栈中的Activity,则它不会收到任何关于LiveData的事件。 -
不需要更多的手动生处理命周期
生命周期状态由LiveData自动管理,无需手动实现。 -
自动获取最新数据
如果生命周期变为活动状态,它将收到最新数据。例如,后台活动在返回到前台后立即收到最新数据。 -
保持数据一致性
重新创建Activity或Fragment(如设备旋转)时,它会立即收到最新的可用数据。 -
共享资源
可以用LiveData单例模式包装系统服务,从而可以在app中共享。LiveData对象仅需连接到系统服务,其他需要该资源的观察者都可获得数据。
我觉学习LiveData会有三个收获:观察者模式、自动更新、生命周期。
观察者模式
关于观察者模式也许并不陌生。这里我们来看看LiveData的观察者模式是怎么实现的。
为了方便理解,我模拟了一套LiveData类,分别是:MyObserver、MyLiveData、MyMediatorLiveData、MyMutableLiveData
。它们都是系统类名字前加了My,结构、成员名都是按照系统类的定义。
模拟的Observer类,名字为MyObserver:
public interface MyObserver<T> {
void onChanged(@Nullable T t);
}
注意:LiveData
使用的Observer是android.arch.lifecycle
包的。
模拟的LiveData类,名字叫MyLiveData:
//包含了LIveData核心的成员。名称都与LiveData保持一致,数据类型也基本相同。
public class MyLiveData<T> {
private static final Object NOT_SET = new Object();
//自己的数据
private volatile Object mData = NOT_SET;
//放观察者的map
private SafeIterableMap<MyObserver<T>, ObserverWrapper> mObservers = new SafeIterableMap<>();
//通知变更,也就是执行观察者的onChanged()方法
private void considerNotify(ObserverWrapper observer) {
observer.mObserver.onChanged((T) mData);
}
//调度值变更,当LiveData数据发生改变时,通过此方法遍历观察者以执行其onChanged()方法
private void dispatchingValue() {
for (@SuppressLint("RestrictedApi")
Iterator<Map.Entry<MyObserver<T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
}
}
//注册观察者
public void observe(@NonNull MyObserver<T> observer) {
ObserverWrapper wrapper = new ObserverWrapper(observer);
//将观察者放入mObservers
mObservers.putIfAbsent(observer, wrapper);
}
public void removeObserver(@NonNull final MyObserver<T> observer) {mObservers.remove(observer); }
//改变数据
public void setValue(T value) {
mData = value;
dispatchingValue();
}
//对Observer的包装类型
private class ObserverWrapper {
final MyObserver<T> mObserver;
ObserverWrapper(MyObserver<T> observer) {
mObserver = observer;
}
}
}
Kotlin实现的MyLiveData:
class MyLiveData<T> {
val NOT_SET = Object()
@Volatile
var mData = NOT_SET as T
var mObservers = SafeIterableMap<MyObserver<T>, ObserverWrapper>()
fun considerNotify(observer: ObserverWrapper): Unit {
observer.mObserver.onChanged(mData as T)
}
fun dispatchingValue() {
for (iterator in mObservers.iteratorWithAdditions())
considerNotify(iterator.value)
}
fun observe(observer: MyObserver<T>) {
var wrapper = ObserverWrapper(observer)
mObservers.putIfAbsent(observer, wrapper)
}
fun removeObserver(observer: MyObserver<T>) {
mObservers.remove(observer)
}
fun setValue(value: T) {
mData = value
dispatchingValue()
}
inner class ObserverWrapper(val mObserver: MyObserver<T>)
}
Kotlin写的有没有清爽很多的感觉。
自己的数据通过mData
成员保存。mObservers
就是保存观察者的map了(不要纠结这个map的类型,现在就把他当成个普通的map就可以了)。
基本原理:
- 通过
observe()
方法将观察者放入mObservers
; - 通过
setValue()
方法更改数据,然后调用dispatchingValue()方法; - dispatchingValue()方法,遍历
mObservers
并逐条执行观察者的onChange()方法;
说到这里,可以对比一下LiveData类了,基本原理就是这样。我们来试试好不好用:
public class MainActivity extends AppCompatActivity {
//MyLiveData类型的数据
MyLiveData<String> mString= new MyLiveData<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/**
*添加了三个观察者
*/
mString.observe(new MyObserver<String>() {
@Override
public void onChanged(@Nullable String s) {
//在这里写数据变更时的处理代码
Log.d("myStep1","观察者1:"+s);
}
});
mString.observe(s -> {
//在这里写数据变更时的处理代码
Log.d("myStep1", "观察者2:" + s);
});
mString.observe(s -> Log.d("myStep1", "观察者3:"+s));
//变更数据
mString.setValue("我来了");
}
}
上面的代码注册了三个观察者,当setValue()
时都执行了自己的onChange()
。
我用了三种写法实现了三个观察者,效果都一样。我觉得还是lambda方便。
Kotlin实现的MainActivity:
class MainActivity : AppCompatActivity() {
var mString: MyLiveData<String> = MyLiveData()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
mString.observe(MyObserver { Log.d("观察者1:", it) })
mString.observe(MyObserver { Log.d("观察者2:", it) })
mString.observe(MyObserver { Log.d("观察者3:", it) })
mString.setValue("我来了")
注意:Java写的MyObserver,才可以用采用上面的传递方式
否则会报错
自动更新
稍微对app结构有要求的场景都需要分层,那么分层后的解耦就很关键。LiveData有个非常适用的特性就是可以给自己增加源,当源发生改变时,会执行更新自己的操作。这就好比各个对象形成了一个链条,当源头改变时,可以一节一节的将改变传输下去,每个节点可自由定义处理更新的方法。
模拟的MediatorLiveData
,名字为MyMediatorLiveData
:
public class MyMediatorLiveData<T> extends MyMutableLiveData<T> {
//存放数据源的map
private SafeIterableMap<MyLiveData<?>, Source<?>> mSources = new SafeIterableMap<>();
//添加数据来源,当然源也必须是LiveData
public <S> void addSource(@NonNull MyLiveData<S> source, @NonNull MyObserver<S> onChanged) {
Source<S> e = new Source<>(source, onChanged);
mSources.putIfAbsent(source, e);
e.plug();//将自己作为观察者,插入到源的观察者map中
}
public <S> void removeSource(@NonNull MyLiveData<S> toRemote) {
Source<?> source = mSources.remove(toRemote);
if (source != null) {
source.unplug();
}
}
private static class Source<V> implements MyObserver<V> {
final MyLiveData<V> mLiveData;
final MyObserver<V> mObserver;
Source(MyLiveData<V> liveData, final MyObserver<V> observer) {
mLiveData = liveData;
mObserver = observer;
}
/**
*将自己作为观察者,插入到源的观察者map中。
*在MediatorLiveData里使用的是observeForever(),后面会详细说
*/
void plug() { mLiveData.observe(this); }
//在源里移除自己
void unplug() {mLiveData.removeObserver(this);}
//当源发生变化时,执行自己定义的onChanged()
public void onChanged(@Nullable V v) {
mObserver.onChanged(v);
}
}
}
这里要说明的最重要机制是内部类Source(MyLiveData<V> liveData, final MyObserver<V> observer)
:
- liveData:来源数据
- observer:自己定义的观察者以及当来源数据发生改变的时候执行的onChange()
- plug():在源上注册自己的观察者
本节内容,说白了就是把自己当成观察者注册到LiveData类型源里。当源数据发生改变,执行自己定义的onChange()改变自己。
模拟的MutableLiveData
,名字为MyMutableLiveData
:
public class MyMutableLiveData<T> extends MyLiveData<T> {
@Override
public void setValue(T value) {
super.setValue(value);
}
}
来看模拟的效果:
public class MainActivity extends AppCompatActivity {
MyMediatorLiveData<String> mString= new MyMediatorLiveData<>();
MyLiveData<String> mSource= new MyLiveData<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//注册观察者
mString.observe(s -> Log.d("myStep2", "1:" + s));
mString.observe(s -> Log.d("myStep2", "2:" + s));
mString.observe(s -> Log.d("myStep2", "3:" + s));
//将自己的setValue()作为onChange()包装成自己的observer,执行添加源操作
mString.addSource(mSource,mString::setValue);
mSource.setValue("我来了");
}
}
这就好比各个LiveData可以环环相扣像链条一样组装起来(中间环节必须是MediatorLiveData
)。在链条每节进行addSource()
时,通过Observer参数里定义onChanged(),可以对中间数据进一步加工。所以会有一个MediatorLiveData。链条的每节在setValue()
时,都会将变更传递到下一环节。
更新控制
有关更新控制首先用到的是LiveData的mVersion
,我们来修改一下MyLiveData:
添加:
static final int START_VERSION = -1;
private int mVersion = START_VERSION;
在MyLiveData的setValue()
添加控制变量:
public void setValue(T value) {
//每次更新都会增加版本号,但并没有提供更新失败的处理
mVersion++;
mData = value;
dispatchingValue();
}
修改MyLiveData的considerNotify()
:
private void considerNotify(ObserverWrapper observer) {
//检查观察者版本,如果大于自身版本,则不会再onChanged()
if (observer.mLastVersion >= mVersion) {return;}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
MyLiveData增加getVersion()
:
int getVersion() {
return mVersion;
}
MyMediatorLiveData的Source
增加int mVersion = START_VERSION;
修改MyMediatorLiveData的onChangend()
:
public void onChanged(@Nullable V v) {
if (mVersion != mLiveData.getVersion()) {
//更新版本信息,也就是说如果执行onChange的时候会改变版本与被源一致
mVersion = mLiveData.getVersion();
mObserver.onChanged(v);
}
}
更新控制仅仅是控制了更新次数,而一旦执行了更新,无论结果如何版本都将强制保持一致。
总结一下
MyObserver
是观察者接口,注册观察者需要实现这个接口。
MyLiveData、MyMutableLiveData、MyMediatorLiveData
使用它们包装的数据类型,作为被观察者类(或内容、订阅)。
MyMutableLiveData
继承自MyLiveData
,表示可变的LiveData
类型。
MyMediatorLiveData
继承自MyMutableLiveData
,表示中介类型。
本篇模拟了LiveData观察者模式的实现机制。但是少了一个重量级因素:与生命周期相关。