Tips: This article is based on the Lifecycle 2.4.0 analysis. The latest release of the Lifecycle component is 2.4.0 as of completion.
Version 2.4.0 Changed
- abandoned
@OnLifecycleEvent
. Should be to switch toLifecycleEventObserver
或DefaultLifecycleObserver
- to
androidx.lifecycle:lifecycle-runtime-ktx
Added new coroutine API:Lifecycle.repeatOnLifecycle
– This API executes a block of code in a coroutine when Lifecycle is in at least one state. Lifecycle will cancel and restart when Lifecycle enters and exits the target state;Flow.flowWithLifecycle
– This API emits values from the upstream flow when Lifecycle is at least in a state.
- Now,
lifecycle-process
useandroidx.startup
To initialize theProcessLifecycleOwner
. Previously this operation was performed byandroidx.lifecycle.ProcessLifecycleOwnerInitializer
The finished.
dependencies {
def lifecycle_version = "2.4.0"
def arch_version = "2.1.0."
// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
// ViewModel utilities for Compose
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version"
// LiveData
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
// Lifecycles only (without ViewModel or LiveData)
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
// Saved state module for ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"
// Annotation processor
kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
// alternately - if using Java8, use the following instead of lifecycle-compiler
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
// optional - helpers for implementing LifecycleOwner in a Service
implementation "androidx.lifecycle:lifecycle-service:$lifecycle_version"
// optional - ProcessLifecycleOwner provides a lifecycle for the whole application process
implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"
// optional - ReactiveStreams support for LiveData
implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:$lifecycle_version"
// optional - Test helpers for LiveData
testImplementation "androidx.arch.core:core-testing:$arch_version"
}
Copy the code
Today we focus to see androidx. Lifecycle: lifecycle – runtime – KTX: $lifecycle_version in content.
LifecycleOwner LifecycleObserver and Lifecycle
Lifecyle components have three cornerstones: Lifecycle, LifecycleObserver and LifecycleOwner. LifecycleObserver, as the name suggests, stands for the observer in the lifecycle:
public interface LifecycleObserver {}Copy the code
LifecycleOwner is the owner of the lifecycle. In Android, both Fragment and ComponentActivity implement this interface:
public interface LifecycleOwner {
@NonNull
Lifecycle getLifecycle(a);
}
Copy the code
Finally Lifecycle, every LifecycleOwner will hold a Lifecycle object that will allow us to obtain the current Lifecycle and add and remove observers:
public abstract class Lifecycle {
public abstract void addObserver(@NonNull LifecycleObserver observer);
public abstract void removeObserver(@NonNull LifecycleObserver observer);
public abstract State getCurrentState(a);
}
Copy the code
Lifecycle also defines two enumerated classes Event and State:
public enum Event {
ON_CREATE,
ON_START,
ON_RESUME,
ON_PAUSE,
ON_STOP,
ON_DESTROY,
ON_ANY;
}
public enum State {
DESTROYED,
INITIALIZED,
CREATED,
STARTED,
RESUMED;
}
Copy the code
The upFrom(), upTo(), downFrom(), downTo(), and getTargetState() methods are provided in the Event class, Used to obtain the events corresponding to the forward and backward conversion of the current State and the State corresponding to the current Event respectively:
@Nullable
public static Event upFrom(@NonNull State state) {
switch (state) {
case INITIALIZED:
return ON_CREATE;
case CREATED:
return ON_START;
case STARTED:
return ON_RESUME;
default:
return null; }}@Nullable
public static Event upTo(@NonNull State state) {
switch (state) {
case CREATED:
return ON_CREATE;
case STARTED:
return ON_START;
case RESUMED:
return ON_RESUME;
default:
return null; }}@NonNull
public State getTargetState(a) {
switch (this) {
case ON_CREATE:
case ON_STOP:
return State.CREATED;
case ON_START:
case ON_PAUSE:
return State.STARTED;
case ON_RESUME:
return State.RESUMED;
case ON_DESTROY:
return State.DESTROYED;
case ON_ANY:
break;
}
throw new IllegalArgumentException(this + " has no target state");
}
Copy the code
The isAtLeast() method is provided in the State class to determine whether the current State is higher than a given minimum State:
public boolean isAtLeast(@NonNull State state) {
return compareTo(state) >= 0;
}
Copy the code
The overall relationship between State and Event is shown in the figure:
Let’s look at the Fragment and ComponentActivity implementation getLifecycle() :
LifecycleRegistry mLifecycleRegistry;
@NonNull
@Override
public Lifecycle getLifecycle(a) {
return mLifecycleRegistry;
}
Copy the code
LifecycleRegistry is the Lifecycle implementation class and there is a bit of code to note:
@Override
public void addObserver(@NonNull LifecycleObserver observer) {
enforceMainThreadIfNeeded("addObserver");
State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
/ / look here
ObserverWithState statefulObserver = newObserverWithState(observer, initialState); ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver); ./ / look hereState targetState = calculateTargetState(observer); mAddingObserverCounter++; .while ((statefulObserver.mState.compareTo(targetState) < 0
&& mObserverMap.contains(observer))) {
pushParentState(statefulObserver.mState);
final Event event = Event.upFrom(statefulObserver.mState);
if (event == null) {
throw new IllegalStateException("no event up from " + statefulObserver.mState);
}
statefulObserver.dispatchEvent(lifecycleOwner, event);
popParentState();
// mState / subling may have been changed recalculatetargetState = calculateTargetState(observer); }... }Copy the code
- This code shows that even if we add a subscriber when State is RESUMED, that subscriber will receive a full stream of ON_CREATE, ON_START, and ON_RESUME events.
Lifecycle can be used with the OnLifecycleEvent annotation prior to 2.4.0:
public class MLifecycleObserver implements LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void onCreate(a) { Log.d(TAG, "onCreate"); }}Copy the code
For Java8, it can be used by implementing DefaultLifecycleObserver. After 2.4.0, OnLifecycleEvent has been deprecated and needs to be replaced with DefaultLifecycleObserver or LifecycleEventObserver:
If both DefaultLifecycleObserver and LifecycleEventObserver are implemented, DefaultLifecycleObserver will be triggered first. LifecycleEventObserver is then triggered.
Everything is ready except the east wind. How does Lifecyle bind to components to capture life cycle changes? Let’s look at the implementation of ComponentActivity:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ReportFragment.injectIfNeededIn(this);
}
Copy the code
ReportFragment. InjectIfNeededIn (this) is the key to:
public static void injectIfNeededIn(Activity activity) {
if (Build.VERSION.SDK_INT >= 29) {
// On API 29+, we can register for the correct Lifecycle callbacks directly
LifecycleCallbacks.registerIn(activity);
}
// Prior to API 29 and to maintain compatibility with older versions of
// ProcessLifecycleOwner (which may not be updated when lifecycle-runtime is updated and
// need to support activities that don't extend from FragmentActivity from support lib),
// use a framework fragment to get the correct timing of Lifecycle events
android.app.FragmentManager manager = activity.getFragmentManager();
if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
manager.beginTransaction().add(new ReportFragment(), REPORT_FRAGMENT_TAG).commit();
// Hopefully, we are the first to make a transaction.manager.executePendingTransactions(); }}Copy the code
repeatOnLifecycle & flowWithLifecycle
FlowWithLifecycle is essentially calling repeatOnLifecycle:
public fun <T> Flow<T>.flowWithLifecycle(
lifecycle: Lifecycle,
minActiveState: Lifecycle.State = Lifecycle.State.STARTED
): Flow<T> = callbackFlow {
lifecycle.repeatOnLifecycle(minActiveState) {
this@flowWithLifecycle.collect {
send(it)
}
}
close()
}
Copy the code
RepeatOnLifecycle implementation is as follows:
public suspend fun Lifecycle.repeatOnLifecycle(
state: Lifecycle.State,
block: suspend CoroutineScope. () - >Unit
){ require(state ! == Lifecycle.State.INITIALIZED) {"repeatOnLifecycle cannot start work with the INITIALIZED lifecycle state."
}
if (currentState === Lifecycle.State.DESTROYED) {
return
}
// This scope is required to preserve context before we move to Dispatchers.Main
coroutineScope {
withContext(Dispatchers.Main.immediate) {
// Check the current state of the lifecycle as the previous check is not guaranteed
// to be done on the main thread.
if (currentState === Lifecycle.State.DESTROYED) return@withContext
// Instance of the running repeating coroutine
var launchedJob: Job? = null
// Registered observer
var observer: LifecycleEventObserver? = null
try {
// Suspend the coroutine until the lifecycle is destroyed or
// the coroutine is cancelled
suspendCancellableCoroutine<Unit> { cont ->
// Lifecycle observers that executes `block` when the lifecycle reaches certain state, and
// cancels when it falls below that state.
val startWorkEvent = Lifecycle.Event.upTo(state)
val cancelWorkEvent = Lifecycle.Event.downFrom(state)
val mutex = Mutex()
observer = LifecycleEventObserver { _, event ->
if (event == startWorkEvent) {
// Launch the repeating work preserving the calling context
launchedJob = this@coroutineScope.launch {
// Mutex makes invocations run serially,
// coroutineScope ensures all child coroutines finish
mutex.withLock {
coroutineScope {
block()
}
}
}
return@LifecycleEventObserver
}
if(event == cancelWorkEvent) { launchedJob? .cancel() launchedJob =null
}
if (event == Lifecycle.Event.ON_DESTROY) {
cont.resume(Unit)}}this@repeatOnLifecycle.addObserver(observer as LifecycleEventObserver)
}
} finally{ launchedJob? .cancel() observer? .let {this@repeatOnLifecycle.removeObserver(it)
}
}
}
}
}
Copy the code
ProcessLifecycleOwner
Lifecycle also provides a ProcessLifecycleOwner to capture the entire Lifecycle of the application, where ON_CREATE occurs only once at creation time, And the ON_DESTROY event never occurs. ON_START, ON_RESUME will be sent when the first activity is triggered; ON_PAUSE and ON_STOP are emitted after a short delay after the last activity is triggered. And you can think about why? This is simply to avoid sending the wrong Event to destroy the rebuild caused by configerationChanged. Then you can do this again when you need to monitor the scenes before and after the application:
ProcessLifecycleOwner.get().lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
super.onStart(owner)
Log.e(TAG,"Come to the front")}override fun onStop(owner: LifecycleOwner) {
super.onStop(owner)
Log.e(TAG,"Go backstage")}})Copy the code