- Lifecycle (I) origins of Android Jetpack architectural components
- Lifecycle (ii) for Android Jetpack architecture components
- Lifecycle (iii) of Android Jetpack architectural components
Lifecycle implementation principle analysis
All source code is based on the latest version of Lifecycle v2.2.0
Lifecycle’s source code is light and lightweight.
Lifecycle’s core design pattern is the observer pattern, which can also be seen through Lifecycle’s approach: addObserver(LifecycleObserver Observer).
One of the interesting things Lifecycle will look at is how the timing of an Activity’s Lifecycle changes is implemented.
Assuming we haven’t seen the source code yet, here’s a guess:
When LifecycleOwner’s method addObserver() is called, it’s easy to think that Lifecycle uses a data structure to store the observer, and then when the Activity’s Lifecycle changes, Lifecycle iterates through this observers collection, calling each observer’s callback method, in which we write our own code. This is easy to think about, but not easy to think about is how Lifecycle accurately timing changes in the Lifecycle
The answer can only be found in the source code
Lifecycle’s source code is roughly divided into two parts:
addObserver()
Register an observer for the view controller- Listen for life cycle changes and notify the observer
The registration process
To register an observer, call getLifecycle().addobServer (LifecycleObserver Observer) in the view controller.
View controllers: Activity and Fragment both implement LifecycleOwner, marking them as components with Lifecylce. First look at getLifecycle() in LifecycleOwner:
public Lifecycle getLifecycle(a)
Copy the code
The return type of this method is Lifecycle. Lifecycle is an abstract class:
public abstract class Lifecycle {
AtomicReference<Object> mInternalScopeRef = new AtomicReference<>();
@MainThread
public abstract void addObserver(@NonNull LifecycleObserver observer);
@MainThread
public abstract void removeObserver(@NonNull LifecycleObserver observer);
@MainThread
public abstract State getCurrentState(a);
@SuppressWarnings("WeakerAccess")
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;
public boolean isAtLeast(@NonNull State state) {
return compareTo(state) >= 0; }}}Copy the code
Lifecycle has three methods and two enumerations. Two enumerations define two core concepts in the Lifecycle Lifecycle: events and states, as described in detail in Lifecycle (2) of the Android Jetpack architecture component. Three methods: Add observer, remove observer, query current status. It also illustrates the major functionality of the Lifecycle class
- Add an observer observer, parse the observer, store it in the collection, and remove the observer when appropriate
- Gets the state of the current LifecycleOwner and is responsible for transitioning between the state and events
Lifecycle is an abstract class and the only concrete implementation class is LifecycleRegistry.
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
LifecycleOwner.ViewModelStoreOwner.{
private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/ / important
ReportFragment.injectIfNeededIn(this);
if(mContentLayoutId ! =0) { setContentView(mContentLayoutId); }}public Lifecycle getLifecycle(a) {
returnmLifecycleRegistry; }}Copy the code
You can see that LifecycleOwner’s method getLifecycle returns exactly LifecycleRegistry in Acitivity.
Start with a few member variables in the LifecycleRegistry class:
public class LifecycleRegistry extends Lifecycle {
/** * Current state */
private State mState;
private FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap =
new FastSafeIterableMap<>();
private final WeakReference<LifecycleOwner> mLifecycleOwner;
private int mAddingObserverCounter = 0;
private boolean mHandlingEvent = false;
}
Copy the code
FastSafeIterableMap
LifecycleRegistry
Stores the collection type of the Observer, which functions through a proxyHashMap
To expand. Similar to theLinkedHashMap
, set elements ordered, through the linked list will each oneEntry
Together. Supports iteration and add and delete operations simultaneouslymLifecycleOwner
Weak references are used here. If theFragmnet
orActivity
中lifecycle
A weak reference is protected from leaking the wholeFramgnet
、Activity
(But we’d better not let that happen in developmentlifecycle
The references are exposed)mAddingObserverCounter
、mHandlingEvent
Two bool values associated with synchronization operations.mState
saidLifecycleOwner
The current state of. whenlifecycle
To detectActivity/Framgnet
When the life cycle of themState
Value, and then callsync()
This method will be otherlifecycle
The data andobservers
For data synchronization, and according tomState
Change distributionmState
The correspondingEvent
.
We then analyze the registration process
The addObserver(LifecycleObserver Observer) method is the entry point to the registration process.
@Override
public void addObserver(@NonNull LifecycleObserver observer) {
State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
LifecycleObserver is converted to LifecycleEventObserver.
ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
// Repeat add, return directly
if(previous ! =null) {
return;
}
/ / found empty
LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
if (lifecycleOwner == null) {
return;
}
// Whether to reenter
booleanisReentrance = mAddingObserverCounter ! =0 || mHandlingEvent;
State targetState = calculateTargetState(observer);
mAddingObserverCounter++;
/ / important
// The initial value of stateFulobServer. mState is
// INITIALIZED, by comparing with the calculated targetState,
// If less than, it enters the loop.
// (DESTROYED is the smallest, INITIALIZED is greater, CREATED is greater, and so on)
while ((statefulObserver.mState.compareTo(targetState) < 0
&& mObserverMap.contains(observer))) {
// Save its own state
pushParentState(statefulObserver.mState);
/ / distribution of the Event
statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
// Delete the state
popParentState();
// Recalculate the state for loop exit conditions until the observer state progresses from the INITIALIZED state to the current LifecyleOwner state
targetState = calculateTargetState(observer);
}
// There is no need to synchronize every time if you reenter, wasting resources, just synchronize once after the last processing of all tasks
if(! isReentrance) {// Update some properties and distribute events
sync();
}
mAddingObserverCounter--;
}
Copy the code
This method starts with the first few lines of code: wrap state and observer as ObserverWithState, INITIALIZED as INITIALIZED, stored in the collection, and returned if the observer already exists. When the added observer is a new one, follow the following process.
The isReentrance Boolean means reentry or not; the isReentrance Boolean means reentry or not;
The process of adding addObserver() is executed at the same time or other Event events are being distributed at the same time.
The synchronization method sync() at the end of the method would not be executed if it were reentrant, because it would be redundant to synchronize every state change during reentrant, just the last one.
Remember the example I gave at the end of the last article? Observe the Activity’s ONSTART event and ONCREATE event in an Observer, and only call addObserver() in the Activity’s onResume(). As a result, the Observer can still be notified of events in the nCreate and onStart life cycles
Lifecycle can do this magic and the logic is in this while loop.
For convenience, the analysis of the while loop is written in comments to the code.
Look at the two methods that are involved in this loop dispatchEvent() and upEvent()
static class ObserverWithState {
State mState;
LifecycleEventObserver mLifecycleObserver;
ObserverWithState(LifecycleObserver observer, State initialState) {
mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
mState = initialState;
}
void dispatchEvent(LifecycleOwner owner, Event event) {
State newState = getStateAfter(event);
mState = min(mState, newState);
// Observer callback functionmLifecycleObserver.onStateChanged(owner, event); mState = newState; }}Copy the code
You can see that dispatchEvent() actually calls the observer’s callback method, where the logic you wrote is executed, and then updates the mState, which is the observer’s State. You can then work with the upEvent() method
private static Event upEvent(State state) {
switch (state) {
case INITIALIZED:
case DESTROYED:
return ON_CREATE;
case CREATED:
return ON_START;
case STARTED:
return ON_RESUME;
case RESUMED:
throw new IllegalArgumentException();
}
throw new IllegalArgumentException("Unexpected state value " + state);
}
Copy the code
And the code comments above should make it easy for you to understand: The observer’s mState is INITIALIZED, and events are continuously distributed forward through upEvent to update the state until the Observer’s mState reaches the mState of the current LifecycleOwner
A complete addObserver() process is complete
LifecycleRegistry as a whole works pretty much as you guessed, so here’s a review
- Add an observer observer, parse the observer, store it in the collection, and remove the observer when appropriate
- Gets the state of the current LifecycleOwner and is responsible for transitioning between the state and events
At the end of the registration process, I actually missed out on how Lifecycle will transform the many different LifecycleObserver implementation classes into a unified LifecycleEventObserver implementation class.
Since it doesn’t have much impact on the main line, I won’t expand on it here. If you are interested, you can read the source code for yourself. The entry is in the addObserver() method, which I have commented out
The notification process
Lifecycle holds all observer references once the registration process is complete, so Lifecycle can be implemented by notifying them all about observers when the Activity \Fragment Lifecycle changes. How does Lifecycle perceive changes in the Activity \Fragment Lifecycle?
There’s actually a weird thing about the ComponentActivity class:
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
LifecycleOwner.ViewModelStoreOwner.{...private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); ./ / here
ReportFragment.injectIfNeededIn(this);
if(mContentLayoutId ! =0) { setContentView(mContentLayoutId); }}... }Copy the code
Follow along to see what the ReportFragment class does:
public class ReportFragment extends Fragment {
public static void injectIfNeededIn(Activity activity) {
// Create a Fragment for @param Activity without a UI
android.app.FragmentManager manager = activity.getFragmentManager();
if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
manager.beginTransaction().add(newReportFragment(), REPORT_FRAGMENT_TAG).commit(); manager.executePendingTransactions(); }}...@Override
public void onActivityCreated(Bundle savedInstanceState) {
dispatch(Lifecycle.Event.ON_CREATE);
}
@Override
public void onStart(a) {
dispatch(Lifecycle.Event.ON_START);
}
@Override
public void onResume(a) {
dispatch(Lifecycle.Event.ON_RESUME);
}
@Override
public void onPause(a) {
dispatch(Lifecycle.Event.ON_PAUSE);
}
@Override
public void onStop(a) {
dispatch(Lifecycle.Event.ON_STOP);
}
@Override
public void onDestroy(a) {
dispatch(Lifecycle.Event.ON_DESTROY);
}
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 instanceofLifecycleRegistry) { ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event); }}}Copy the code
After reading here, I suddenly see. By injecting an Activity with a ReportFragment without a UI, and then writing the Dispathch () method in each ReportFragment lifecycle callback that corresponds to the Activity ** dispatches changes to the lifecycle state. Because a Fragment depends on the Activity that created it, the Fragment’s Lifecycle is synchronized with the Activity’s Lifecycle, thus indirectly implementing the ability for Lifecycle to listen to the Activity’s Lifecycle. Then look at how events are distributed by dispatch() :
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 instanceofLifecycleRegistry) { ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event); }}}Copy the code
LifecycleOwner is forced upward after calling getActivity(), and the handleLifecycleEvent() of the LifecycleRegistry class is called, The logic goes back to the LifecycleRegistry class, where events are distributed back to LifecycleRegistry
Look at an implementation of handleLifecycleEvent(Event) :
public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
State next = getStateAfter(event);
moveToState(next);
}
Copy the code
Convert the distributed Event to State and then call moveToState() :
private void moveToState(State next) {
// Update mState to the current StatemState = next; . mHandlingEvent =true;
sync();
mHandlingEvent = false;
}
Copy the code
After updating the value of mState, sync() is called. This method is an important one in the LifecycleRegistry class.
Note that event is distributed, updating mSate without calling observers with the onStateChanged() callback.
All operations are handed over to the sync() method to synchronize and distribute events based on mState changes.
private void sync(a) { LifecycleOwner lifecycleOwner = mLifecycleOwner.get(); .// Determine whether synchronization is required. If no synchronization is required, continue
while(! isSynced()) { mNewEventOccurred =false;
if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
// Synchronize and distribute events
backwardPass(lifecycleOwner);
}
Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
if(! mNewEventOccurred && newest ! =null
&& mState.compareTo(newest.getValue().mState) > 0) {
// Synchronize and distribute events
forwardPass(lifecycleOwner);
}
}
mNewEventOccurred = false;
}
Copy the code
The first step is to determine whether synchronization is needed by calling isSynced(), which is very simple to implement.
private boolean isSynced(a) {
if (mObserverMap.size() == 0) {
return true;
}
State eldestObserverState = mObserverMap.eldest().getValue().mState;
State newestObserverState = mObserverMap.newest().getValue().mState;
return eldestObserverState == newestObserverState && mState == newestObserverState;
}
Copy the code
From the previous introduction we learned that the data structure that stores the Observer is an ordered Map.
By comparing the mState values of the first observer and the last observer, the synchronization is completed if the mState values are equal. If the mState values are not equal, the synchronization continues until the mState values are equal.
If the state of the first observer is equal to that of the last observer, the mSate of all intermediate observers must also be equal, thus marking the completion of synchronization.
In the forwardPass (lifecycleOwner) and forwardPass (lifecycleOwner); Method, we finally call the much-anticipated callback method: onStateChanged(), where our code is executed.
The whole process is analyzed.