Android移动架构汇总
LiveData是一种可观察的数据存储器类,它具有生命周期感知能力,可确保LiveData仅更新处于活跃生命周期的应用组件观察者。
* LiveData is a data holder class that can be observed within a given lifecycle.
* This means that an {@link Observer} can be added in a pair with a {@link LifecycleOwner}, and
* this observer will be notified about modifications of the wrapped data only if the paired
* LifecycleOwner is in active state. LifecycleOwner is considered as active, if its state is
* {@link Lifecycle.State#STARTED} or {@link Lifecycle.State#RESUMED}. An observer added via
* {@link #observeForever(Observer)} is considered as always active and thus will be always notified
* about modifications. For those observers, you should manually call
* {@link #removeObserver(Observer)}.
*
* An observer added with a Lifecycle will be automatically removed if the corresponding
* Lifecycle moves to {@link Lifecycle.State#DESTROYED} state. This is especially useful for
* activities and fragments where they can safely observe LiveData and not worry about leaks:
* they will be instantly unsubscribed when they are destroyed.
*
*
* In addition, LiveData has {@link LiveData#onActive()} and {@link LiveData#onInactive()} methods
* to get notified when number of active {@link Observer}s change between 0 and 1.
* This allows LiveData to release any heavy resources when it does not have any Observers that
* are actively observing.
*
* This class is designed to hold individual data fields of {@link ViewModel},
* but can also be used for sharing data between different modules in your application
* in a decoupled fashion.
*
* @param The type of data held by this instance
* @see ViewModel
dependencies {
...
def lifecycle_version = "2.3.1"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
...
}
LiveData为抽象类,MutableLiveData为LiveData子类,在ViewModel中定义
public class ElecSignatureModel extends ViewModel {
private MutableLiveData<ElecSignature> mutableLiveData;
public class ElecSignatureModel extends ViewModel {
mutableLiveData = new MutableLiveData<>();
}
}
MutableLiveData数据赋值有两种方式,分别为postValue和setValue。这两种方式的区别在于应用场景有所不同,即当设置数据操作在子线程中时使用前者,在UI线程时则使用后者
public void getElcState() {
ElectronicRepository.getInstance().getElcSignatureState(new DisposableCallBack<ElecSignature>() {
@Override
public void onSubscribe() {
loadingLiveData.setValue(true);
}
@Override
public void onDispose() {
loadingLiveData.setValue(false);
}
@Override
public void onError(Throwable e) {
loadingLiveData.setValue(false);
//ToastUtil.show("获取是否签署电子签名约定书请求失败");
}
@Override
public void onSuccess(ElecSignature data) {
loadingLiveData.setValue(false);
mutableLiveData.setValue(data);
}
@Override
public void onFailed(String msg) {
loadingLiveData.setValue(false);
mutableLiveData.setValue(null);
}
});
}
public LiveData<ElecSignature> getMutableLiveData() {
return mutableLiveData;
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewModel = ViewModelProviders.of(this).get(ElecSignatureModel.class);
binding = DataBindingUtil.setContentView(this, R.layout.activity_elec_signature);
binding.navigationBar.setTitle("电子签名约定书");
//订阅
viewModel.getMutableLiveData().observe(this, new Observer<ElecSignature>() {
@Override
public void onChanged(@Nullable ElecSignature signature) {
//TODO
}
});
.....
//请求数据
viewModel.getElcState();
}
通过map转化,可以将某种LiveData类型的数据转换为另一种类型。当只需要知道一个对象的成员变量是否发生变化,可以用map
**
* Applies the given function on the main thread to each value emitted by {@code source}
* LiveData and returns LiveData, which emits resulting values.
* <p>
* The given function {@code func} will be executed on the main thread.
* <p>
* Suppose that you have a LiveData, named {@code userLiveData}, that contains user data and you
* need to display the user name, created by concatenating the first and the last
* name of the user. You can define a function that handles the name creation, that will be
* applied to every value emitted by {@code useLiveData}.
*
* <pre>
* LiveData<User> userLiveData = ...;
* LiveData<String> userName = Transformations.map(userLiveData, user -> {
* return user.firstName + " " + user.lastName
* });
* </pre>
*
* @param source a {@code LiveData} to listen to
* @param func a function to apply
* @param <X> a type of {@code source} LiveData
* @param <Y> a type of resulting LiveData.
* @return a LiveData which emits resulting values
*/
@MainThread
public static <X, Y> LiveData<Y> map(@NonNull LiveData<X> source,
@NonNull final Function<X, Y> func) {
final MediatorLiveData<Y> result = new MediatorLiveData<>();
result.addSource(source, new Observer<X>() {
@Override
public void onChanged(@Nullable X x) {
result.setValue(func.apply(x));
}
});
return result;
}
switchMap转化是将从外部如网络层获取的LiveData转化为可观察的方式
/**
* Creates a LiveData, let's name it {@code swLiveData}, which follows next flow:
* it reacts on changes of {@code trigger} LiveData, applies the given function to new value of
* {@code trigger} LiveData and sets resulting LiveData as a "backing" LiveData
* to {@code swLiveData}.
* "Backing" LiveData means, that all events emitted by it will retransmitted
* by {@code swLiveData}.
*
* If the given function returns null, then {@code swLiveData} is not "backed" by any other
* LiveData.
*
*
* The given function {@code func} will be executed on the main thread.
*
*
* Consider the case where you have a LiveData containing a user id. Every time there's a new
* user id emitted, you want to trigger a request to get the user object corresponding to that
* id, from a repository that also returns a LiveData.
*
* The {@code userIdLiveData} is the trigger and the LiveData returned by the {@code
* repository.getUserById} is the "backing" LiveData.
*
* In a scenario where the repository contains User(1, "Jane") and User(2, "John"), when the
* userIdLiveData value is set to "1", the {@code switchMap} will call {@code getUser(1)},
* that will return a LiveData containing the value User(1, "Jane"). So now, the userLiveData
* will emit User(1, "Jane"). When the user in the repository gets updated to User(1, "Sarah"),
* the {@code userLiveData} gets automatically notified and will emit User(1, "Sarah").
*
* When the {@code setUserId} method is called with userId = "2", the value of the {@code
* userIdLiveData} changes and automatically triggers a request for getting the user with id
* "2" from the repository. So, the {@code userLiveData} emits User(2, "John"). The LiveData
* returned by {@code repository.getUserById(1)} is removed as a source.
*
*
* MutableLiveData userIdLiveData = ...;
* LiveData userLiveData = Transformations.switchMap(userIdLiveData, id ->
* repository.getUserById(id));
*
* void setUserId(String userId) {
* this.userIdLiveData.setValue(userId);
* }
*
*
* @param trigger a {@code LiveData} to listen to
* @param func a function which creates "backing" LiveData
* @param a type of {@code source} LiveData
* @param a type of resulting LiveData
*/
@MainThread
public static <X, Y> LiveData<Y> switchMap(@NonNull LiveData<X> trigger,
@NonNull final Function<X, LiveData<Y>> func) {
final MediatorLiveData<Y> result = new MediatorLiveData<>();
result.addSource(trigger, new Observer<X>() {
LiveData<Y> mSource;
@Override
public void onChanged(@Nullable X x) {
LiveData<Y> newLiveData = func.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;
}
LiveData的本质是观察者模式
/**
* Adds the given observer to the observers list within the lifespan of the given
* owner. The events are dispatched on the main thread. If LiveData already has data
* set, it will be delivered to the observer.
*
* The observer will only receive events if the owner is in {@link Lifecycle.State#STARTED}
* or {@link Lifecycle.State#RESUMED} state (active).
*
* If the owner moves to the {@link Lifecycle.State#DESTROYED} state, the observer will
* automatically be removed.
*
* When data changes while the {@code owner} is not active, it will not receive any updates.
* If it becomes active again, it will receive the last available data automatically.
*
* LiveData keeps a strong reference to the observer and the owner as long as the
* given LifecycleOwner is not destroyed. When it is destroyed, LiveData removes references to
* the observer & the owner.
*
* If the given owner is already in {@link Lifecycle.State#DESTROYED} state, LiveData
* ignores the call.
*
* If the given owner, observer tuple is already in the list, the call is ignored.
* If the observer is already in the list with another owner, LiveData throws an
* {@link IllegalArgumentException}.
*
* @param owner The LifecycleOwner which controls the observer
* @param observer The observer that will receive the events
*/
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
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);
}
从代码中可以看到,observe方法首先会通过@MainThread当前是否运行在主线程,且LiveData和生命周期相关联,如果想让数据监测变化不受活动状态的影响,可以使用observeForever方法,这样Activity即使不处于活动状态,也可以接收到改变的数据,但当Activity销毁时,一定要主动调用removeObserver方法,否则LiveData会一直存在,这会导致内存泄漏。
observe与LifecycleOwner关联起来存放在LifecycleBoundObserver中,LifecycleBoundObserver实现了LifecycleEventObserver接口,当页面发生改变的时候,程序会走到onStateChanged方法中。具体代码如下
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
页面被销毁时会调用removeObserver移除观察,所以使用LiveData的observe方法不用担心存在内存泄漏的风险。如果之前的周期与当前不同,则会同步一次状态,并调用activeStateChanged方法,而activeStateChanged方法则会调用dispatchingValue方法分发数据。dispatchingValue方法的代码如下:
private 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<T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
通过使用mDispatchingValue变量标记来防止分发相同的内容,通过循环方式遍历所有的观察者,通过considerNotify方法更新数据。
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);
}
如果观察者已经不属于活动状态,直接返回,并通过比较数据的版本号判断数据是否需要更新。如果需要更新则会回调到observer的onChanged方法中,从而实现在UI层接收数据的回调。
版本号何时更新?看设置数据的setValue方法
/**
* Sets the value. If there are active observers, the value will be dispatched to them.
*
* This method must be called from the main thread. If you need set a value from a background
* thread, you can use {@link #postValue(Object)}
*
* @param value The new value
*/
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
setValue方法时,数据版本号改变,通过dispatching-Value方法进行数据处理,从而实现了LiveData的可观察