目录
- 前言
- 一、LiveData粘性原因分析
- 1.1 发送消息流程
- 1.2 监听消息流程
- 1.3 根因分析
- 二、hook解决
前言
在 Android 中,LiveData 的默认行为是粘性的,即 LiveData 在设置数据后,即使观察者订阅时已经有数据存在,观察者仍会立即收到这个数据。
在上一篇文章中JetPack之LiveData最后的案例我们看到了livedata的粘性事件
,一般情况下,我们观察者先订阅,等到消息发生改变时,接收到消息,使用observe做一些更新UI等操作,但是粘性事件会导致我们会接收到订阅之前的数据,这在某些场景下并不是我们想要的。
一、LiveData粘性原因分析
1.1 发送消息流程
MutableLiveData
的两个发送消息流程setValue、postValue。
setValue 只能在主线程使用,postValue可以在任何线程使用,它被调用时,其实也是通过handler切换到了主线程,再调用 的setValue
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
setValue((T) newValue);
}
};
setValue 首先声明自己要在主线程中运行,然后 mVersion
++;,最后调用dispatchingValue分发消息
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
dispatchingValue
方法主要是对参数中的观察者进行了判空以及遍历,最后对每个遍历的对象调用了considerNotify
方法
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<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
considerNotify
首先判断观察者是否存活,如果观察者不处于活动状态,则直接返回,不通知观察者。
- 检查观察者是否应该处于活动状态。如果观察者不应该处于活动状态,则调用 activeStateChanged(false) 方法通知观察者状态已更改,并返回,不通知观察者。
检查观察者上一次接收到的版本号是否大于或等于 LiveData 的当前版本号。如果是,则表示观察者已经接收过最新的数据,无需再次通知观察者。
- 如果不是最新版本号,将 LiveData 的当前版本号赋值给观察者的上一次版本号,表示观察者已经接收到最新的数据。
- 调用观察者的 onChanged 方法,将 LiveData 中存储的数据 mData 传递给观察者进行处理。
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;
observer.mObserver.onChanged((T) mData);
}
发送消息流程基本解读完毕,读到这里,有几个核心点:
1.
mLastVersion
:上一个版本号
2.mVersion
当前版本号
3.如果当前版本号不是最新版本号,那么版本号会被覆盖,然后回调观察者的onChanged方法,即我们更新UI等操作的地方
接下来看监听流程
1.2 监听消息流程
从监听的observe方法入手
- assertMainThread(“observe”);: 检查当前线程是否为主线程,如果不是主线程则抛出异常。这是为了确保 observe 方法在主线程中调用,因为 LiveData 的观察者通常在主线程中更新 UI。
- if (owner.getLifecycle().getCurrentState() == DESTROYED) { return; }: 检查生命周期所有者的当前状态是否为 DESTROYED(已销毁),如果是,则直接返回,不执行后续操作。
- LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);: 创建一个 LifecycleBoundObserver 对象,将生命周期所有者和观察者传入。
- ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);: 将观察者和对应的 LifecycleBoundObserver 对象放入 mObservers Map 中,如果之前已经存在相同的观察者则返回已存在的 ObserverWrapper 对象。
- 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);: 将 LifecycleBoundObserver 对象添加到生命周期所有者的 Lifecycle 中,这样当生命周期所有者的状态发生变化时,会通知绑定的观察者。
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
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);
}
从 LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);入手,看一下内部做了什么
LifecycleBoundObserver 继承了 ObserverWrapper ,实现了 LifecycleEventObserver 接口。
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
.......
LifecycleEventObserver 当 lifecycle 状态改变的时候会感应到,并进行回调onStateChanged方法
public fun interface LifecycleEventObserver : LifecycleObserver {
/**
* Called when a state transition event happens.
*
* @param source The source of the event
* @param event The event
*/
public fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event)
}
当onStateChanged的状态改变传递到LifecycleBoundObserver时,会调用LifecycleBoundObserver的onStateChanged方法
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
if (currentState == DESTROYED) {
removeObserver(mObserver);
return;
}
Lifecycle.State prevState = null;
while (prevState != currentState) {
prevState = currentState;
activeStateChanged(shouldBeActive());
currentState = mOwner.getLifecycle().getCurrentState();
}
}
最终回调到ObserverWrapper 的activeStateChanged方法,观察一下ObserverWrapper类结构,原来之前的mLastVersion
是在这里定义的,默认值为-1,回到activeStateChanged方法,可以看到最终也会回到 dispatchingValue方法,只是负责分发当前观察者(this),不像发送消息流程分发到全部的观察者。
public abstract class LiveData<T> {
@SuppressWarnings("WeakerAccess") /* synthetic access */
final Object mDataLock = new Object();
static final int START_VERSION = -1;
@SuppressWarnings("WeakerAccess") /* synthetic access */
private abstract class ObserverWrapper {
final Observer<? super T> mObserver;
boolean mActive;
int mLastVersion = START_VERSION;
ObserverWrapper(Observer<? super T> observer) {
mObserver = observer;
}
abstract boolean shouldBeActive();
boolean isAttachedTo(LifecycleOwner owner) {
return false;
}
void detachObserver() {
}
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive;
changeActiveCounter(mActive ? 1 : -1);
if (mActive) {
dispatchingValue(this);
}
}
}
1.3 根因分析
mLastVersion 的默认初始值是-1,mVersion 的默认初始值也是-1,当我们先执行发送的时候,进行了自增,mVersion 就变成了0,当我们执行observe 进行监听的时候,observer.mLastVersion >= mVersion 这个条件就不成立了,因为此时mLastVersion 是-1,小于 mVersion 了。
发送和监听都会调用dispatchingValue
方法,但mVersion
只要发送就会在setValue方法中++,而mLastVersion
永远只能在setValue方法后的considerNotify方法中被置为mVersion的值。
public LiveData() {
mData = NOT_SET;
mVersion = START_VERSION;
}
public abstract class LiveData<T> {
@SuppressWarnings("WeakerAccess") /* synthetic access */
final Object mDataLock = new Object();
static final int START_VERSION = -1;
二、hook解决
在安卓开发中,“Hook” 是指通过修改系统或应用程序的行为,来实现某种特定的功能或者改变程序的默认行为。常见的 Hook 技术包括方法 Hook、类 Hook、系统 Hook 等。以下是对安卓 Hook 的详细解释:
方法 Hook
:
方法 Hook 是指在程序运行时替换或者修改某个方法的实现逻辑,以达到特定的目的。
通过方法 Hook,可以拦截系统或第三方库的方法调用,修改方法的参数或返回值,实现功能增强或者数据篡改等操作。
常见的方法 Hook 框架有 Xposed、Dexposed、Frida 等。
类 Hook
:
类 Hook 是指在程序运行时替换或者修改某个类的实现逻辑,以达到特定的目的。
通过类 Hook,可以修改类的属性、方法行为,实现功能增强或者数据篡改等操作。
类 Hook 通常需要使用字节码操作技术,如 ASM、Javassist 等。
系统 Hook
:
系统 Hook 是指修改系统层的行为,如修改系统服务、系统调用等,以实现对系统行为的控制。
通过系统 Hook,可以实现系统级别的功能增强、权限管理、安全加固等操作。
系统 Hook 需要对系统底层进行深入了解,通常需要 root 权限才能实现。
Hook 的应用场景:
功能增强:通过 Hook 修改系统或应用程序的行为,实现功能增强或定制化功能。
数据篡改:通过 Hook 修改数据传递或处理逻辑,实现数据篡改或数据劫持。
安全加固:通过 Hook 检测恶意行为、加固系统安全,防止恶意软件的攻击。
调试分析:通过 Hook 获取程序运行时的信息,进行调试分析或性能优化。
我们使用hook反射的方式,在每次Observe方法中,将mLastVersion
赋值为mVersion
,这样下次就不会调用到onChanged
方法中,去除了粘性!
核心代码
private void hook(Observer<? super T> observer) {
try {
Field mObserversField = LiveData.class.getDeclaredField("mObservers");
mObserversField.setAccessible(true);
Object mObserversObject = mObserversField.get(this);
Class<?> mObserversClass = mObserversObject.getClass();
Method get = mObserversClass.getDeclaredMethod("get", Object.class);
get.setAccessible(true);
Object invokeEntry = get.invoke(mObserversObject, observer);
Object observerWrapper = null;
if (invokeEntry != null && invokeEntry instanceof Map.Entry) {
observerWrapper = ((Map.Entry) invokeEntry).getValue();
}
if (observerWrapper == null) {
throw new NullPointerException("observerWrapper is null");
}
Log.d("Henry","属性是什么"+ observerWrapper.getClass());
Class<?> superClass = observerWrapper.getClass().getSuperclass();
Field mLastVersion = superClass.getDeclaredField("mLastVersion");
mLastVersion.setAccessible(true);
Field mVersion = LiveData.class.getDeclaredField("mVersion");
mVersion.setAccessible(true);
Object mVersionValue = mVersion.get(this);
mLastVersion.set(observerWrapper, mVersionValue);
} catch (Exception e) {
e.printStackTrace();
}
}
示例:采取反射,先发消息后订阅,不会接受到旧消息。
OkLiveDataBusJava.java
public class OkLiveDataBusJava {
//存放订阅者
private static final Map<String, BusMutableLiveData<?>> bus = new HashMap<>();
public synchronized static <T> BusMutableLiveData<T> with(String key, Class<T> type, boolean ishook) {
if (!bus.containsKey(key)) {
bus.put(key, new BusMutableLiveData<>(ishook));
}
return (BusMutableLiveData<T>) bus.get(key);
}
public static class BusMutableLiveData<T> extends MutableLiveData<T> {
private boolean ishook;
private BusMutableLiveData(boolean ishook) {
this.ishook = ishook;
}
@Override
public void observe(LifecycleOwner owner, Observer<? super T> observer) {
super.observe(owner, observer);
if (ishook) {
hook(observer);
Log.d("Henry", " 启用hook");
} else {
Log.d("Henry", " 不启用hook");
}
}
private void hook(Observer<? super T> observer) {
try {
Field mObserversField = LiveData.class.getDeclaredField("mObservers");
mObserversField.setAccessible(true);
Object mObserversObject = mObserversField.get(this);
Class<?> mObserversClass = mObserversObject.getClass();
Method get = mObserversClass.getDeclaredMethod("get", Object.class);
get.setAccessible(true);
Object invokeEntry = get.invoke(mObserversObject, observer);
Object observerWrapper = null;
if (invokeEntry != null && invokeEntry instanceof Map.Entry) {
observerWrapper = ((Map.Entry) invokeEntry).getValue();
}
if (observerWrapper == null) {
throw new NullPointerException("observerWrapper is null");
}
Log.d("Henry","属性是什么"+ observerWrapper.getClass());
Class<?> superClass = observerWrapper.getClass().getSuperclass();
Field mLastVersion = superClass.getDeclaredField("mLastVersion");
mLastVersion.setAccessible(true);
Field mVersion = LiveData.class.getDeclaredField("mVersion");
mVersion.setAccessible(true);
Object mVersionValue = mVersion.get(this);
mLastVersion.set(observerWrapper, mVersionValue);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
OkLiveDataBusActivity
public class OkLiveDataBusActivity extends AppCompatActivity {
Button button;
@SuppressLint("MissingInflatedId")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ok_live_data_bus);
button = findViewById(R.id.OKlivedata_jump);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(OkLiveDataBusActivity.this,
OkLiveDataBusSecondActivity.class));
}
});
OkLiveDataBusJava.with("data", String.class, true).postValue("old 数据-----------");
}
}
OkLiveDataBusSecondActivity
public class OkLiveDataBusSecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ok_live_data_bus_second);
OkLiveDataBusJava.with("data", String.class, true).observe(this,
new Observer<String>() {
@Override
public void onChanged(String s) {
Toast.makeText(OkLiveDataBusSecondActivity.this,
"获取数据" + s, Toast.LENGTH_SHORT).show();
}
});
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
OkLiveDataBusJava.with("data", String.class, true).postValue("new 数据-----------");
}
}).start();
}
}
测试一下:
来张美图犒劳一下