-
Notifications
You must be signed in to change notification settings - Fork 121
UnPeekLiveData v3 设计思路
KunMinX edited this page Jun 13, 2022
·
5 revisions
以下源码设计,及对设计思路理解和解析,属于参与过源码设计讨论有效贡献者及本人共同成果,我们对此享有所有权和最终解释权。
任何个人或组织在引用以下内容时,须注明原作者和链接出处。未经授权不得用于洗稿、广告包装、卖课等商业用途。
Copyright 2019-present KunMinX
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
/*
* Copyright 2018-present KunMinX
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.kunminx.architecture.ui.callback;
import androidx.annotation.NonNull;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.Observer;
import java.util.Timer;
import java.util.TimerTask;
/**
* UnPeekLiveData 的存在是为在 "重回二级页面" 场景下,解决 "数据倒灌" 问题。
* 对 "数据倒灌" 状况不理解小伙伴,可参考《LiveData 数据倒灌 背景缘由全貌 独家解析》解析
*
* https://xiaozhuanlan.com/topic/6719328450
*
* 本类参考官方 SingleEventLive 非入侵设计,
*
* 并创新引入 "延迟清空消息" 设计,
* 如此可确保:
* 1.一条消息能被多个观察者消费
* 2.延迟期结束,不再能够收到旧消息推送
* 3.且旧消息在延迟期结束时能从内存中释放,避免内存溢出等问题
* 4.让非入侵设计成为可能,遵循开闭原则
*
* 增加一层 ProtectedUnPeekLiveData,
* 用于限制从 Activity/Fragment 推送数据,推送数据务必通过唯一可信源来分发,
* 如这么说无体会,详见:
* https://xiaozhuanlan.com/topic/6719328450 和 https://xiaozhuanlan.com/topic/0168753249
*
* Create by KunMinX at 19/9/23
*/
@Deprecated
public class ProtectedUnPeekLiveDataV3<T> extends LiveData<T> {
private boolean isCleaning;
private boolean hasHandled = true;
private boolean isDelaying;
protected int DELAY_TO_CLEAR_EVENT = 1000;
private Timer mTimer = new Timer();
private TimerTask mTask;
protected boolean isAllowNullValue;
protected boolean isAllowToClear = true;
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
super.observe(owner, t -> {
if (isCleaning) {
hasHandled = true;
isDelaying = false;
isCleaning = false;
return;
}
if (!hasHandled) {
hasHandled = true;
isDelaying = true;
observer.onChanged(t);
} else if (isDelaying) {
observer.onChanged(t);
}
});
}
/**
* UnPeekLiveData 主要用于表现层 页面转场 和 页面间通信 场景非粘性消息分发,
* 出于生命周期安全等考虑,不建议使用 observeForever 方法,
*
* 对于数据层工作,如有需要,可结合实际场景使用 MutableLiveData 或 kotlin flow。
*
* @param observer
*/
@Override
public void observeForever(@NonNull Observer<? super T> observer) {
throw new IllegalArgumentException("Do not use observeForever for communication between pages to avoid lifecycle security issues");
}
/**
* 重写的 setValue 方法,默认不接收 null
* 可通过 Builder 配置允许接收
* 可通过 Builder 配置消息延时清理时间
*
* override setValue, do not receive null by default
* You can configure to allow receiving through Builder
* And also, You can configure the delay time of message clearing through Builder
*
* @param value
*/
@Override
protected void setValue(T value) {
if (!isCleaning && (!isAllowNullValue && value == null)) {
return;
}
hasHandled = false;
isDelaying = false;
super.setValue(value);
if (mTask != null) {
mTask.cancel();
mTimer.purge();
}
if (value != null) {
mTask = new TimerTask() {
@Override
public void run() {
clear();
}
};
mTimer.schedule(mTask, DELAY_TO_CLEAR_EVENT);
}
}
private void clear() {
if (isAllowToClear) {
isCleaning = true;
super.postValue(null);
} else {
hasHandled = true;
isDelaying = false;
}
}
}
package com.kunminx.architecture.ui.callback;
/**
* Note 2020.10.15:
* 这是第 3 代 UnPeekLiveData 设计,目前最新版本为更少隐患的第 4 代。
*
* UnPeekLiveData 的存在是为在 "重回二级页面" 场景下,解决 "数据倒灌" 问题。
* 对 "数据倒灌" 状况不理解小伙伴,可参考《LiveData 数据倒灌 背景缘由全貌 独家解析》解析
*
* https://xiaozhuanlan.com/topic/6719328450
*
* 本类参考官方 SingleEventLive 非入侵设计,
*
* 并创新引入 "延迟清空消息" 设计,
* 如此可确保:
* 1.一条消息能被多个观察者消费
* 2.延迟期结束,不再能够收到旧消息推送
* 3.且旧消息在延迟期结束时能从内存中释放,避免内存溢出等问题
* 4.让非入侵设计成为可能,遵循开闭原则
*
* 增加一层 ProtectedUnPeekLiveData,
* 用于限制从 Activity/Fragment 推送数据,推送数据务必通过唯一可信源来分发,
* 如这么说无体会,详见:
* https://xiaozhuanlan.com/topic/6719328450 和 https://xiaozhuanlan.com/topic/0168753249
*
* Create by KunMinX at 2020/7/21
*/
@Deprecated
public class UnPeekLiveDataV3<T> extends ProtectedUnPeekLiveDataV3<T> {
@Override
public void setValue(T value) {
super.setValue(value);
}
@Override
public void postValue(T value) {
super.postValue(value);
}
public static class Builder<T> {
/**
* 消息生存时长
*/
private int eventSurvivalTime = 1000;
/**
* 是否允许传入 null value
*/
private boolean isAllowNullValue;
/**
* 是否允许自动清理,默认 true
*/
private boolean isAllowToClear = true;
public Builder<T> setEventSurvivalTime(int eventSurvivalTime) {
this.eventSurvivalTime = eventSurvivalTime;
return this;
}
public Builder<T> setAllowNullValue(boolean allowNullValue) {
this.isAllowNullValue = allowNullValue;
return this;
}
public Builder<T> setAllowToClear(boolean allowToClear) {
this.isAllowToClear = allowToClear;
return this;
}
public UnPeekLiveDataV3<T> create() {
UnPeekLiveDataV3<T> liveData = new UnPeekLiveDataV3<>();
liveData.DELAY_TO_CLEAR_EVENT = this.eventSurvivalTime;
liveData.isAllowNullValue = this.isAllowNullValue;
liveData.isAllowToClear = this.isAllowToClear;
return liveData;
}
}
}