Jetpack:Lifecycle 和 LiveData

在讲解 Lifecycle 和 LiveData 之前,有必要说明下 Jetpack,官方对 Jetpack 的描述如下:

Jetpack 是一个由多个库组成的套件,可帮助开发者遵循最佳做法、减少样板代码并编写可在各种 Android 版本和设备中一致运行的代码,让开发者可将精力集中于真正重要的编码工作。

简单理解 Jetpack,它是由多个库组成的、版本兼容的、让我们专注于业务代码的套件。

其中 Lifecycle 和 LiveData 是 Jetpack 中的两个组件,也是比较重要的两个库;LiveData 使用了 Lifecycle,所以我们会先从 Lifecycle 开始讲起,然后再讲解 LiveData,这样会更方便原理。

Lifecycle

Lifecycle 的使用

我们可以先思考一个问题:为什么需要 Lifecycle?

在没有 Lifecycle 之前,如果我们实现 MVP 架构,要在 Presenter 能知道 Activity 的生命周期,一般会这么写:

public interface ILifecycle {
	void onCreate();
	
	void onDestroy();
}

public class MyPresenter implements ILifecycle {
	@Override
	public void onCreate() {}

	@Override
	public void onDestroy() {}
}

public class MainActivity extends AppCompatActivity {
	private Presenter presenter;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCraete(savedInstanceState);
		presenter = new MyPresenter();
		presenter.onCreate();
	}
	
	@Override
	protected void onDestroy() {
		super.onDestroy();
		presenter.onDestroy();
	}
}

这种其实都是样板代码,虽然也能实现但却存在一些问题:

  • 编码疏忽没有及时移除引用,容易产生内存泄漏

  • 和 Activity 耦合侵入性强,只要有改动其他 Activity 都要修改,不好维护

所以 Google 为了我们能更专注的写业务代码,提供了 Lifecycle。

Lifecycle 是根据观察者模式设计的,既然是观察者模式,就有观察者和被观察者。其中 被观察者需要实现 LifecycleOwner 接口,观察者需要实现 LifecycleObserver 接口

在 Android 已经默认将 Activity/Fragment 实现 LifecycleOwner 作为被观察者,当 Activity/Fragment 的生命周期变化时,就会通知到观察者。

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
	LifecycleOwner,
	ViewModelStoreOwner,
	SavedStateRegistryOwner,
	OnBackPressedDispatcherOwner {
	...
}

public class MyClass implements LifecycleObserver {
	
	// 各个生命周期调用通知
	@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
	void onCreate(LifecycleOwner owner) {}

	@OnLifecycleEvent(Lifecycle.Event.ON_START)
	void onStart(LifecycleOwner owner) {}

	@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
	void onResume(LifecycleOwner owner) {}
	
	@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
	void onPause(LifecycleOwner owner) {}

	@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
	void onStop(LifecycleOwner owner) {}

	@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
	void onDestroy(LifecycleOwner owner) {}
}

被观察者需要能通知到观察者,两者还要建立订阅关系。只需要在 Activity/Fragment 调用 getLifecycle().addObserver() 将观察者传入参数即可:

public class MyActivity extends AppCompatActivity {
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		MyClass myclass = new MyClass();
		getLifecycle().addObserver(myClass);
	}
}

Lifecycle 的使用非常简单,只需要建立订阅关系,观察者就能在生命周期变化时收到通知,而取消订阅 Lifecycle 已经帮我们做了处理,这能有效的帮助我们解决编码疏忽导致内存泄漏的隐患。

Lifecycle 的实现原理

Lifecycle 订阅观察者是使用 getLifecycle().addObserver(),具体看下它做了什么事情:

Lifecycle.java

public abstract class Lifecycle {
	...
	
    @MainThread
    public abstract void addObserver(@NonNull LifecycleObserver observer);	
}

LifecycleRegistry.java

@Override
public void addObserver(@NonNull LifecycleObserver observer) {
	// 这里有一个 mState 的状态,我们后面讲
	State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
	// 将我们传进来的 LifecycleObserver 包装成新的对象
	ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
	// 将我们传进来的 LifecycleObserver 作为 key,包装对象为 value 存进 map
	ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
	...
}

addObserver() 第一步是将我们传进来的 LifecycleObserver 包装成一个新对象,然后将包装对象又存进了 mObserverMap。mObserverMap 存放了订阅了 Activity 的所有观察者

为什么要对观察者再包装一层呢?我们看下 ObserverWithState 做了什么事情:

LifecycleRegistry.java

static class ObserverWithState {
	State mState;
	LifecycleEventObserver mLifecycleObserver;
	
	ObserverWithState(LifecycleObserver observer, State initialState) {
		mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
		mState = initialState;
	}
	...
}

Lifecycling.java

@NonNull
static LifecycleEventObserver lifecycleEventObserver(Object object) {
	...
	return new ReflectiveGenericLifecycleObserver(object);
}

ReflectiveGenericLifecycleObserver.java

class ReflectiveGenericLifecycleObserver implements LifecycleEventObserver {
	private final Object mWrapped;
	private final CallbackInfo mInfo;
	
	ReflectiveGenericLifecycleObserver(Object wrapped) {
		mWrapped = wrapped;
		mInfo = ClassesInfoCache.sInstance.getInfo(mWrapped.getClass());	
	}
}

ClassInfoCache.java

CallbackInfo getInfo(Class klass) {
	CallbackInfo existing = mCallbackMap.get(klass);
	if (existing != null) {
		return existing;
	}
	existing = createInfo(klass, null);
	return existing;
}

private CallbackInfo createInfo(Class klass, @Nullable Method[] declaredMethods) {
	Map<MethodReference, Lifecycle.Event> handlerToEvent = new HashMap<>();
	...
	// 获取到观察者对象的所有方法
	Method[] methods = declaredMethods != null ? declaredMethods : getDeclaredMethods(klass);
	boolean hasLifecycleMethods = false;
	for (Method method : methods) {
		// 找到所有添加了 @OnLifecycleEvent 注解的方法
		OnLifecycleEvent annotation = method.getAnnotation(OnLifecycleEvent.class);
		if (annotation == null) {
			continue;
		}
		hasLifecycleMethods = true;
		Class<?>[] params = method.getParameterTypes();
		// CALL_TYPE_NO_ARG = 0
		// CALL_TYPE_PROVIDER = 1
		// CALL_TYPE_PROVIDER_WITH_EVENT = 2
		int callType = CALL_TYPE_NO_ARG;
		if (params.length > 0) {
			callType = CALL_TYPE_PROVIDER;
			...
		}
		Lifecycle.Event event = annotation.value();
		if (params.length > 1) {
			callType = CALL_TYPE_PROVIDER_WITH_EVENT;
			...
		}
		...
		// 将观察者所有带了 @OnLifecycleEvent 注解的方法存到 handlerToEvent 这个 map
		MethodReference methodReference = new MethodReference(callType, method);
		verifyAndPutHandler(handlerToEvent, methodReference, event, klass);
	}
	// 所以 CallbackInfo 持有了观察者所有添加了 @OnLifecycleEvent 的方法
	CallbackInfo info = new CallbackInfo(handlerToEvent);
	...
	return info;
}

ObserverWithState 这个包装对象在创建时主要做了一件事情:将观察者对象 class 的所有带 @OnLifecycleEvent 注解的方法都找出来存到一个 map,将 map 包装为 CallbackInfo

按照这种设计我们可以猜测,在 Activity/Fragment 生命周期改变的时候,就可以先找到 mObserverMap 拿到所有的观察者,然后找到 ObserverWithState 的 mInfo 反射调用添加了 @LifecycleEvent 注解的方法。这样就能完成生命周期变化时的通知:

在这里插入图片描述

现在只是完成观察者和被观察者建立订阅的操作,那么生命周期是怎么通知到观察者的?

ComponentActivity.java

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	...
	ReportFragment.injectIfNeededIn(this);
	...
}

ReportFragment.java

public static void injectIfNeededIn(Activity activity) {
	// ProcessLifecycleOwner should always correctly work and some activities may not extend
	// FragmentActivity from support lib, so we use framework fragments for activities
	android.app.FragmentManager manager = activity.getFragmentManager();
	if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
		manager.beginTransaction().add(new ReportFragment(), REPORT_FRAGMENT_TAG).commit();
		manager.executePendingTransactions();	
	}

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        dispatchCreate(mProcessListener);
        dispatch(Lifecycle.Event.ON_CREATE);
    }

    @Override
    public void onStart() {
        super.onStart();
        dispatchStart(mProcessListener);
        dispatch(Lifecycle.Event.ON_START);
    }

    @Override
    public void onResume() {
        super.onResume();
        dispatchResume(mProcessListener);
        dispatch(Lifecycle.Event.ON_RESUME);
    }

    @Override
    public void onPause() {
        super.onPause();
        dispatch(Lifecycle.Event.ON_PAUSE);
    }

    @Override
    public void onStop() {
        super.onStop();
        dispatch(Lifecycle.Event.ON_STOP);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        dispatch(Lifecycle.Event.ON_DESTROY);
        // just want to be sure that we won't leak reference to an activity
        mProcessListener = null;
    }


    private void dispatch(Lifecycle.Event event) {
        Activity activity = getActivity();
        if (activity instanceof LifecycleRegistryOwner) {
            ((LifecycleRegistryOwner) activity).getLifecycle().handleLifecycleEvent(event);
            return;
        }

        if (activity instanceof LifecycleOwner) {
            Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();
            if (lifecycle instanceof LifecycleRegistry) {
                ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);
            }
        }
    }
    ...
}

看过 Glide 源码的话就会很清楚上面做了什么事情,生命周期变化通知观察者并不是直接在 Activity 的生命周期方法直接下发的通知,而是额外创建了一个没有界面的 ReportFragment,将生命周期变化的通知委托给它处理

为什么不直接在 Activity 的生命周期下做通知,在 ReportFragment 的 injectIfNeedIn() 方法有注释说明:

ProcessLifecycleOwner should always correctly work and some activities may not extend
FragmentActivity from support lib, so we use framework fragments for activities

因为考虑到用户并不是所有的 Activity 都继承自 FragmentActivity,所以做了兼容用一个 Fragment 代为转发生命周期变化的通知

LifecycleRegistry.java

public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
	State next = getStateAfter(event); // 这里用到了状态机
	moveToState(next);	
}

private void moveToState(State next) {
	...
	mState = next; // 将状态记录下来
	sync();
	...
}

private void sync() {
	LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
	...
	while (!isSynced()) {
		...
		if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
			backwardPass(lifecycleOwner);
		}
		Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
		if (!mNewEventOccurred && newest != null
				&& mState.compareTo(newest.getValue().mState) > 0) {
			forwardPass(lifecycleOwner);
		}
	}
	mNewEventOccurred = false;
}

private void backwardPass(LifecycleOwner lifecycleOwner) {
    Iterator<Entry<LifecycleObserver, ObserverWithState>> descendingIterator =
            mObserverMap.descendingIterator();
    while (descendingIterator.hasNext() && !mNewEventOccurred) {
    	// 找到 mObserverMap 拿到观察者下发通知
		Entry<LifecycleObserver, ObserverWithState> entry = descendingIterator.next();
		ObserverWithState observer = entry.getValue();
		while ((observer.mState.compareTo(mState) < 0 && !mNewEventOccurred
				&& mObserverMap.contains(entry.getKey()))) {
			// 根据状态拿到要分发的生命周期事件	
			Event event = downEvent(observer.mState);	
			...
			observer.dispatchEvent(lifecycleOwner, event);
		}
	} 
}

private void forwardPass(LifecycleOwner lifecycleOwner) {
    Iterator<Entry<LifecycleObserver, ObserverWithState>> ascendingIterator =
            mObserverMap.iteratorWithAdditions();
    while (ascendingIterator.hasNext() && !mNewEventOccurred) {
    	// 找到 mObserverMap 拿到观察者下发通知
		Entry<LifecycleObserver, ObserverWithState> entry = ascendingIterator.next();
		ObserverWithState observer = entry.getValue();
		while ((observer.mState.compareTo(mState) < 0 && !mNewEventOccurred
				&& mObserverMap.contains(entry.getKey()))) {
			...
			// upEvent():根据状态拿到要分发的生命周期事件	
			observer.dispatchEvent(lifecycleOwner, upEvent(observer.mState));
		}
	} 
}

static class ObserverWithState {
	State mState;
	LifecycleEventObserver mLifecycleObserver;
	...
	void dispatchEvent(LifecycleOwner owner, Event event) {
		...
		// 经过上面源码的分析已经知道 mLifecycleObserver 就是 ReflectiveGenericLifecycleObserver
		mLifecycleObserver.onStateChanged(owner, event);
		...
	}
}

ReflectiveGenericLifecycleObserver.java

class ReflectiveGenericLifecycleObserver implements LifecycleEventObserver {
	private final Object mWrapped;
	private final CallbackInfo mInfo;
	...
    @Override
    public void onStateChanged(LifecycleOwner source, Event event) {
		mInfo.invokeCallbacks(source, event, mWrapped);
	}
}

ClassInfoCache.java

static class CallbackInfo {
	...
	final Map<MethodReference, Lifecycle.Event> mHandlerToEvent;
	...

	void invokeCallbacks(LifecycleOwner source, Lifecycle.Event event, Object target) {
		invokeMethodsForEvent(mEventToHandlers.get(event), source, event, target);
		invokeMethodsForEvent(mEventToHandlers.get(Lifecycle.Event.ON_ANY), source, event,
				target);
	}

    private static void invokeMethodsForEvent(List<MethodReference> handlers,
            LifecycleOwner source, Lifecycle.Event event, Object mWrapped) {
        if (handlers != null) {
            for (int i = handlers.size() - 1; i >= 0; i--) {
                handlers.get(i).invokeCallback(source, event, mWrapped);
            }
        }
    }
}

static class MethodReference {
	final int mCallType;
	final Method mMethod;
	...
	void invokeCallback(LifecycleOwner source, Lifecycle.Event event, Object target) {
        try {
            switch (mCallType) {
                case CALL_TYPE_NO_ARG:
                    mMethod.invoke(target);
                    break;
                case CALL_TYPE_PROVIDER:
                    mMethod.invoke(target, source);
                    break;
                case CALL_TYPE_PROVIDER_WITH_EVENT:
                    mMethod.invoke(target, source, event);
                    break;
            }
        } catch (InvocationTargetException e) {
            throw new RuntimeException("Failed to call observer method", e.getCause());
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }		
	}
}

在分析 mObserverMap 和 mInfo 时我们就已经基本猜测了大致的调用流程,这里看源码更多的是验证我们的猜测是否正确:

  • 找到 mObserverMap 拿到订阅的观察者,调用 dispatchEvent(lifecycleOwner, event) 下发通知

  • 最终就是找到 mInfo 存储的添加了 @OnLifecycleEvent 注解的方法反射调用

我们再完善下 Lifecycle 的核心流程图解:

在这里插入图片描述

对应的调用时序图如下:

在这里插入图片描述

Lifecycle 如何使用状态机管理生命周期

还有一个问题没有解决:Lifecycle 是怎样确定要分发在哪个生命周期方法的?

当 ReportFragment 将对应的事件下发通知时,根据上面的时序图是先去 LifecycleRegistry 做了一次状态同步的操作,然后再下发生命周期事件,都在 handleLifecycleEvent() 完成:

在这里插入图片描述

这里实际上用到了状态机的机制,我们看下状态图:

在这里插入图片描述

单纯看状态图可能不好理解,我们将状态图和代码放一起对比着看会比较好理解一些。首先第一步是根据传过来的生命周期事件获取当前的状态:

在这里插入图片描述

我们举个例子理解下,当 Activity/Fragment 创建从不显示到显示,即状态图从左往右的流程,ReportFragment 执行完了 onActivityCreate(),dispatchEvent() 就会下发生命周期事件 ON_CREATE,所以这里执行到 getStateAfter() 获得的状态就是 CREATED。

在 forwardPass() 和 backwardPass() 分别会调用 upEvent() 和 downEvent(),根据当前状态获取生命周期事件:

在这里插入图片描述

因为 mState 的状态已经是 CREATED,所以执行 upEvent() 时通知下一个生命周期事件是 ON_START。

简单小结下,handleLifecycleEvent() 其实做了两件事情

  • 根据 ReportFragment 下发的生命周期事件获取当前状态并记录下状态

  • 将状态同步给所有观察者,下发生命周期事件给到观察者

所以 handleLifecycleEvent() 做的事情就是将状态同步给观察者。

到这里 Lifecycle 的原理已经分析完毕。

LiveData

LiveData 的使用

LiveData 是一种具有生命周期感知能力的可观察数据持有类,可以保证屏幕上的显示内容和数据保持同步,在默认情况下它只会在界面显示的时候即 onStart() 后才会接收到通知消息更新 UI

LiveData 的使用非常简单,在项目中一般会配合着 ViewModel 使用:

public class MyViewModel extends ViewModel {
	private MutableLiveData<Boolean> _liveData = new MutableLiveData<>();
	LiveData<Boolean> liveData = _liveData;

	public void request() {
		...
		// liveData.postValue(true); // 非 UI 线程使用
		liveData.setValue(true);
	}
}

public class MainActivity extends AppCompatActivity {
	private MyViewModel viewModel = new MyViewModel();
	
	@Override
	protected void onCreate(@Nullable Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		viewModel.liveData.observe(this, new Observer<Boolean>() {
			@Override
			public void onChanged(Boolean changed) {
			}
		});

		viewModel.request();
	}
}

如果想在界面不可见时也要能接收到消息,LiveData 也提供了 observeForever:

public class MainActivity extends AppCompatActivity {
	private MyViewModel viewModel = new MyViewModel();
	
	private Observer<Boolean> observer;
	
	@Override
	protected void onCreate(@Nullable Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		observer = new Observer<Boolean>() {
			@Override
			public void onChanged(Boolean changed) {
			}
		};
		viewModel.liveData.observeForever(observer);

		viewModel.request();
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		// 界面销毁时移除,避免内存泄漏
		viewModel.liveData.removeObserver(observer);
	}
}

使用 observeForever() 时已经不具备有 Lifecycle 清除的功能,在界面销毁时要手动移除 Observer,避免内存泄漏。

LiveData 也是基于 Lifecycle 实现的一个组件,所以它具备监听 Activity/Fragment 的生命周期变化,也就是它是一个观察者;同样的它又具备发消息的操作,所以它也是一个被观察者

在这里插入图片描述

LiveData 的订阅

LiveData 在使用上没有看到哪里使用了 Lifecycle,怎么就能监听到生命周期变化了?接下来我们从源码开始分析了解它的实现原理。

首先我们从 observe() 调用开始分析:

LiveData.java

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
	...
	// 将我们传入的 Observer 做了一次包装
	LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
	// 用我们的 observer 作为 key,包装对象作为 value 存到 map
	ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
	...
	// LifecycleBoundObserver 能被订阅,说明它肯定实现了 LifecycleObserver
	// 被观察者和观察者建立订阅关系
	owner.getLifecycle().addObserver(wrapper);
}

class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
	...
}

GenericLifecycleObserver.java

@Deprecated
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
public interface GenericLifecycleObserver extends LifecycleEventObserver {
}

LifecycleEventObserver.java

// 实现了 LifecycleObserver
public interface LifecycleEventObserver extends LifecycleObserver {
	...
}

observe() 主要就做一件事情:建立订阅关系

将我们创建的 Observer 包装为 LifecycleBoundObserver 对象,同样的它也是一个 LifecycleObserver,LifecycleBoundObserver 的作用就是把观察者和被观察者包装在一起绑定作为 Activity/Fragment 的观察者

mObservers 存放了一个 LiveData 的所有 Observer,一个 LiveData 可以有多个 Observer,这也间接证明了它是一个被观察者,因为需要通知一个或多个观察者

LiveData 粘性事件及 hook 实现非粘性功能

完成了订阅,就可以用 LiveData 调用 setValue() 发消息:

LiveData.java

// 添加了 volatile,说明 mData 是有可能在并发环境下操作
private volatile Object mData = NOT_SET;

// 版本管理,主要用于数据处理
private int mVersion = START_VERSION;

@MainThread
protected void setValue(T value) {
	assertMainThread("setValue");
	mVersion++; // 每次发消息都更新 mVersion
	mData = value; // 每次发消息数据都先更新
	dispatchingValue(null); 
}

void dispatchingValue(@Nullable ObserverWrapper initiator) {
    if (mDispatchingValue) {
        mDispatchInvalidated = true;
        return;
    }	
    mDispatchingValue = true;
    do {
		mDispatchInvalidated = false;
		// 不为空时只通知指定的观察者
		if (initiator != null) {
			considerNotify(initiator);
			initiator = null;
		} else {
			// 通知所有 observer 观察者
			for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
					mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
				considerNotify(iterator.next().getValue()); 
				if (mDispatchInvalidated) {
					break;
				}
			}
		}
	} while (mDispatchInvalidated);
	mDispatchingValue = false;
}

private void considerNotify(ObserverWrapper observer) {
	// 当生命周期是 onStart()/onResume() 时 mActive = true
    if (!observer.mActive) {
        return;
    }

	// LifecycleBoundObserver.shouldBeActive()
	// 当生命周期是 onStart()/onResume() 时为 true
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    // 判断数据的版本是否一致
    // 如果 观察者的数据版本 >= 被观察者的版本,不处理
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;
    //noinspection unchecked
    observer.mObserver.onChanged((T) mData);
}

class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
	...
    @Override
    boolean shouldBeActive() {
    	// 至少是界面可见,即生命周期会在 onStart()/onResume() 时返回 true
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    }
}

setValue() 其实就是通知订阅的观察者更新,dispatchingValue() 会根据传入的参数有不同的处理

  • 如果传入的参数为 null,会遍历通知所有的观察者

  • 如果传入的参数不为 null,会通知指定的观察者

considerNotify() 通知数据更新会经过几个判断

  • observer.mActive、observer.shouldBeActive():界面需要可见,即生命周期有调用过 onStart()/onResume()

  • observer.mLastVersion >= mVersion:观察者的数据版本不能大于被观察者

分析了 observe.mActive 和 observer.shouldBeActive() 的源码,我们知道 观察者订阅后将会在界面可见时即 onStart() 之后才调用 observer.onChanged() 收到通知

public class MainActivity extends AppCompatActivity {

	@Override
	protected void onCreate(@Nullable Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		viewModel.liveData.observe(this, new Observer<Boolean>() {
			@Override
			public void onChanged(Boolean changed) {
				// 在 onStart() 之后调用
			}
		});
	}
}

我们主要看 observer.mLastVersion >= mVersion,为什么需要版本对比?有什么作用?

LiveData.java

private int mVersion = START_VERSION; // -1

@MainThread
protected void setValue(T value) {
	assertMainThread("setValue");
	mVersion++; // 每调用一次 setValue() 版本 +1
	mData = value;
	dispatchingValue(null);
}

使用 LiveData 可能会出现两种流程:

  • 创建 LiveData -> 订阅 -> 发消息

  • 创建 LiveData -> 发消息 -> 订阅

主要看第二种情况,当还没有调用 liveData.observe() 建立订阅关系时,此时不断的调用 setValue(),每次 setValue() 都会更新 mVersion 和 mData;LiveData 为了能做到多次更新只接收最新的数据,就需要对数据做版本处理,这样建立订阅关系时,观察者就能收到最新的数据。这就是做版本对比的目的

class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
	...
    @Override
    boolean shouldBeActive() {
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    }

    @Override
    public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
    	// 界面销毁时就帮我们移除观察者,避免内存泄漏
        if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
            removeObserver(mObserver);
            return;
        }
        activeStateChanged(shouldBeActive());
    }
}

private abstract class ObserverWrapper {
    void activeStateChanged(boolean newActive) {
        if (newActive == mActive) {
            return;
        }
        // immediately set active state, so we'd never dispatch anything to inactive
        // owner
        mActive = newActive; 
        boolean wasInactive = LiveData.this.mActiveCount == 0;
        LiveData.this.mActiveCount += mActive ? 1 : -1;
        if (wasInactive && mActive) {
            onActive(); // 提供给自定义 LiveData 处理界面可见时的钩子
        }
        if (LiveData.this.mActiveCount == 0 && !mActive) {
            onInactive(); // 提供给自定义 LiveData 处理界面不可见时的钩子
        }
        // 将 mActive 更新为 true,并通知观察者
        if (mActive) {
            dispatchingValue(this);
        }
    }	
}

在这里插入图片描述

当我们尝试把 LiveData 当成事件总线来使用的时候,按 创建 LiveData -> 发消息 -> 订阅 这种流程时,你会发现是有问题的:当我们多次发送消息,LiveData 此时还记录着消息,所以一旦有观察者订阅并界面可见时,就会收到这条消息。这也就是 LiveData 的粘性事件

public class LiveDataBus {
    private final Map<String, MutableLiveData<Object>> bus;

    private static final LiveDataBus sInstance = new LiveDataBus();

    private LiveDataBus() {
        bus = new HashMap<>();
    }

    public static LiveDataBus getInstance() {
        return sInstance;
    }

    public synchronized <T> MutableLiveData<T> with(String key, Class<T> type) {
        if (!bus.containsKey(key)) {
            bus.put(key, new MutableLiveData<>());
        }
        return (MutableLiveData<T>) bus.get(key);
    }
}

public class MainActivity extends AppCompatActivity {

	@Override
	protected void onCreate(@Nullable Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		button.setOnClicklistener(new OnClickListener() {
			@Override
			public void onClick(View view) {
				LiveDataBus.getInstance().with("msg", String.class).setValue("1");
				startActivity(new Intent(MainActivity.this, SecondActivity.class));
			}
		});
	}
}

public class SecondActivity extends AppCompatActivity {

	@Override
	protected void onCreate(@Nullable Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
			
		LiveDataBus.getInstance().with("msg", String.class).observe(this, new Observer<String>() {
			@Override
			public void onChanged(String s) {
				Log.i("SecondActivity", "s = " + s);
			}
		});
	}
}

当然粘性事件并不是 bug,而是使用不当导致的问题。因为 LiveData 正常的使用流程是 创建 LiveData -> 订阅 -> 发消息,而不是 创建 LiveData -> 发消息 -> 订阅。粘性事件出现的原因就是发消息比订阅提前了

如果你觉得我就是要这么玩把 LiveData 作为事件总线,又不想订阅的时候就收到订阅前发送的消息,那该怎么做呢?我们重新分析下通知观察者的源码:

LiveData.java

private void considerNotify(ObserverWrapper observer) {
    if (!observer.mActive) {
        return;
    }

    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    
    // 可以从 mLastVersion 修改,让界面进入时 mLastVersion 符合这个判断就能跳过
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;
    //noinspection unchecked
    observer.mObserver.onChanged((T) mData);
}

因为 observer.mActive 和 observer.shouldBeActive() 都是和生命周期有关的处理不好修改容易出问题,所以切入口就是 observer.mLastVersion 和 mLastVersion,当建立订阅时符合判断条件把处理 return 就能解决粘性事件了。要做到这个效果需要 hook 修改它们的数值

具体 hook 代码如下:

public class NonStickyMutableLiveData<T> extends MutableLiveData<T> {
	private boolean stickFlag;

    @Override
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        super.observe(owner, observer);
        if (!stickFlag) {
			stickFlag = true;
			hook(observer);
		}
    }

    private void hook(Observer<? super T> observer) {
        try {
            // 拿到 mObservers
            Field mObserversField = LiveData.class.getDeclaredField("mObservers");
            mObserversField.setAccessible(true);
            Object mObserversObject = mObserversField.get(this);

            // 调用 mObservers.get(observer) 得到 Map.Entry
            Class<?> mObserversClass = mObserversObject.getClass();
            Method get = mObserversClass.getDeclaredMethod("get", Object.class);
            get.setAccessible(true);
            Object invokeEntry = get.invoke(mObserversObject, observer);

            // 拿到 mObservers 的 value = ObserverWrapper
            Object observerWrapper = null;
            if (invokeEntry instanceof Map.Entry) {
                observerWrapper = ((Map.Entry) invokeEntry).getValue();
            }
            if (observerWrapper == null) {
                throw new NullPointerException("observerWrapper is null");
            }

            // 获取 observer.mLastVersion
            Class<?> superclass = observerWrapper.getClass().getSuperclass();
            Field mLastVersionField = superclass.getDeclaredField("mLastVersion");
            mLastVersionField.setAccessible(true);

            // 获取 mVersion
            Field mVersionField = LiveData.class.getDeclaredField("mVersion");
            mVersionField.setAccessible(true);
            Object mVersion = mVersionField.get(this);

            // 将 observer.mLastVersion 修改为和 mVersion
            mLastVersionField.set(observerWrapper, mVersion);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

所以如果我们要支持非粘性功能的 LiveData 作为事件总线,就可以使用上面的 hook 实现:

public class LiveDataBus {
    private final Map<String, MutableLiveData<Object>> bus;

    private static final LiveDataBus sInstance = new LiveDataBus();

    private LiveDataBus() {
        bus = new HashMap<>();
    }

    public static LiveDataBus getInstance() {
        return sInstance;
    }

	// 粘性 LiveData
    public synchronized <T> MutableLiveData<T> with(String key, Class<T> type) {
        if (!bus.containsKey(key)) {
            bus.put(key, new MutableLiveData<>());
        }
        return (MutableLiveData<T>) bus.get(key);
    }

	// 提供非粘性功能实现的 LiveData
    public synchronized <T> NonStickyMutableLiveData<T> withNonSticky(String key, Class<T> type) {
        if (!bus.containsKey(key)) {
            bus.put(key, new NonStickyMutableLiveData<>());
        }
        return (NonStickyMutableLiveData<T>) bus.get(key);
    }
}

LiveData 递归调用如何实现的容错

LiveData 还有最后一个知识点,假设我们在代码中递归发送消息,会发生什么?

public class MainActivity extends AppCompatActivity {
	private final MutableLiveData<String> liveData = new MutableLiveData<>();

	@Override
	protected void onCreate(@Nullable Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		liveData.observe(this, new Observer<String>() {
			@Override
			public void onChanged(@Nullable String s) {
				Log.i("MainActivity", "s = " + s); 
				if ("1".equals(s)) {
					liveData.setValue("2"); // 递归调用,收到消息 1 后接着发送消息 2
				}
			}
		});
		
		liveData.observe(this, new Observer<String>() {
			@Override
			public void onChanged(@Nullable String s) {
				Log.i("MainActivity", "s = " + s); 
			}
		});		
	
		btn.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View view) {
				liveData.setValue("1");
			}
		});
	}
}

预想结果:
1
1
2
2

结果:
1
2
2

最终发送的结果并不是我们所预想的那样,而是只接收到一次 1,后续的都是最新的数据 2。LiveData 是怎么做到递归容错的?

还记得源码中发送通知的 dispatchingValue() 方法吗,第一次看源码的时候会觉得很奇怪为什么会这么写:

LiveData.java

private boolean mDispatchingValue;

private boolean mDispatchInvalidated;

void dispatchingValue(@Nullable ObserverWrapper initiator) {
	// 用了两个变量 mDispatchingValue 和 mDispatchInvalidated,干嘛用的?
    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;  
}

在方法中使用了两个变量 mDispatchingValue 和 mDispatchInvalidated,这两个变量也只有在这里使用到,而这两个变量就是 LiveData 处理递归容错的关键

为了方便步骤说明,这里我们把两个观察者名为 observer A 和 observer B 分别代表第一个和第二个订阅的观察者。

我们按 demo 的操作按步骤分析:

在这里插入图片描述

总结

该篇文章详细的讲解了 Lifecycle 和 LiveData 从使用到实现原理。

Lifecycle 是基于观察者设计模式实现的框架,Lifecycle 的生命周期分发是使用了没有 UI 的 ReportFragment,在各个生命周期回调方法下分发状态;Lifecycle 也巧妙的使用了状态机的机制分发生命周期的状态,最终的目的是将生命周期状态同步给观察者。

LiveData 是基于 Lifecycle 实现,它既是观察者同时也是被观察者,一般配合着 ViewModel 使用作为数据和 UI 绑定的桥梁。我们也详细分析了 LiveData 的粘性事件,它并不是 bug 而是正常的逻辑处理,原因是在使用 LiveData 的流程上出了问题,比如将 LiveData 用于做事件总线,可以通过 hook 解决;也分析了 LiveData 对递归消息的容错处理,也值得我们学习。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值