series
Back to Jetpack: Dependencies and transitive relationships of Jetpack’s major components
Changes to using activities and fragments under AdroidX
Can you really use a Fragment? Fragments FAQ and new postures for using fragments on androidx
AndroidX Fragment1.2.2 Source code analysis
Fragment returns the stack preparation section
Jetpack’s Fragment return stack is a Fragment return stack demo
Never lose the state of AndroidX SaveState ViewModel-SaveState analysis
Even if you don’t use MVVM, understand the ViewModel — the functional boundaries of the ViewModel
preface
There is an important concept in Android: “life cycle.” When you go to an interview right out of college, you’re often asked the “lifecycle of the four components” question. At IO 2017, Google launched Lifecycle Aware Components to help developers organize better, lighter, and easier to maintain code
This article will give you an insight into the responsibilities of Lifecycle and a brief analysis of how Lifecycle feels about activities and fragments
Everything is based on Lifecycle
You don’t understand the pain of managing the life cycle manually
Lu Xun once said: Everything is based on Lifecycle
Oh no
View controllers in Android have this many life cycles, so it’s important to get the life cycle right, otherwise it can lead to memory leaks and even crashes. Here is an example of official documentation
class MyLocationListener {
public MyLocationListener(Context context, Callback callback) {
// ...
}
void start(a) {
// Connect to the system location service
}
void stop(a) {
// The system is disconnected from the location service}}class MyActivity extends AppCompatActivity {
private MyLocationListener myLocationListener;
@Override
public void onCreate(...). {
myLocationListener = new MyLocationListener(this, (location) -> {
/ / update the UI
});
}
@Override
public void onStart(a) {
super.onStart();
myLocationListener.start();
// Manage other components that need to respond to the activity lifecycle
}
@Override
public void onStop(a) {
super.onStop();
myLocationListener.stop();
// Manage other components that need to respond to the activity lifecycle}}Copy the code
This example looks good; in a real application, you would still make too many calls to manage the UI and other components in response to the current state of the life cycle. Managing multiple components puts a lot of code in lifecycle methods, such as onStart() and onStop(), which makes them difficult to maintain
Also, there is no guarantee that the component will start before the activity or fragment stops. If we need an operation that takes a long time to run (such as some configuration check in onStart()), we may result in a race situation where the onStop() method completes before onStart(), making the component live longer than it needs to.
class MyActivity extends AppCompatActivity {
private MyLocationListener myLocationListener;
public void onCreate(...). {
myLocationListener = new MyLocationListener(this, location -> {
/ / update the UI
});
}
@Override
public void onStart(a) {
super.onStart();
Util.checkUserStatus(result -> {
// What if this callback is called after the activity has stopped?
if(result) { myLocationListener.start(); }}); }@Override
public void onStop(a) {
super.onStop(); myLocationListener.stop(); }}Copy the code
It would be nice to have all the components aware of the external life cycle, able to release resources at the appropriate time, and stop asynchronous tasks when the life cycle is missed.
Let’s start by thinking about how to implement such an idea
Think conventionally
First, let’s sort out our requirements
- Internal components are aware of external life cycles
- Can be unified management, so that a modification, everywhere effective
- Be able to call off missed tasks
For requirement 1, the observer pattern can be used so that internal components can respond as the external lifecycle changes
For requirement 2, component-dependent code can be moved out of the lifecycle methods and into the components themselves, so that only the internal logic of the components can be modified
For requirement 3, the observer can be removed at the appropriate time
Observer model
The first time I looked at the observer mode in detail was in the Drop line RxJava tutorial for Android developers.
The observer mode is oriented to the requirement that object A (observer) is highly sensitive to A certain change of object B (observed) and needs to respond at the moment when B changes. For example, in the news, the police catch a thief. The police need to catch the thief when he reaches for his hand. In this example, the policeman is the observer and the thief is the observed. The policeman needs to keep an eye on the thief’s every move to ensure that no moment is missed. The observer mode of the program is slightly different from this kind of real “observation”. The observer does not need to stare at the observed all the time (for example, A does not need to check the status of B every 2ms), but registers, or subscribes, to tell the observed: I need your status, and you need to let me know when it changes. A typical example of this in Android development is the OnClickListener. For OnClickListener, the View is the observed and OnClickListener is the observer, and the subscription relationship is achieved through the setOnClickListener() method. The moment the user clicks a button after subscribes, the Android Framework sends the click event to the registered OnClickListener. Adopting this passive observation mode not only saves the resource consumption of repeatedly retrieving the state, but also can get the highest feedback speed. Of course, this also benefits from the fact that we can customize the observer and observed in our own program, while the police obviously cannot ask the thief to “inform me when you commit a crime”.
The OnClickListener mode looks like this:
The above description and images are from the RxJava detail for Android developers
Therefore, the internal component is aware of the external lifecycle by telling the observer when the lifecycle of the lifecycle component changes
After introducing the Lifecycle
public class MyObserver implements LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void connectListener(a) {... }@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void disconnectListener(a) {... } } myLifecycleOwner.getLifecycle().addObserver(new MyObserver());
Copy the code
Source structure
Lifecycle this is the structure of Lifecycle, an abstract class with two enumerations inside representing ‘events’ and’ states’ and three methods to add/remove observers and get the current state
Note that the enumeration order in State here makes sense, as described later
The implementation class is LifecycleRegistry and can handle multiple observers
It holds the current state, mState, LifecycleOwner, and a custom list of observers internally, overwriting the parent class’s methods for adding/removing observers
LifecycleOwner, which has the Android lifecycle, custom components can use these events to handle lifecycle changes without implementing any code in an Activity or Fragment
LifecycleObserver, which marks a class as LifecycleObserver. It doesn’t have any methods and instead relies on the methods of the OnLifecycleEvent annotation
LifecycleEventObserver, which can receive any lifecycle changes and dispatch them to recipients.
If a class implements this interface and also uses OnLifecycleEvent, annotations are ignored
DefaultLifecycleObserver, a callback interface for listening for LifecycleOwner state changes.
If a class implements both this interface and LifecycleEventObserver, the DefaultLifecycleObserver method is first called, Then call LifecycleEventObserver. OnStateChanged (LifecycleOwner, Lifecycle. The Event)
Note: Using DefaultLifecycleObserver needs to be introduced
implementation “androidx.lifecycle:lifecycle-common-java8:$lifecycle_version”
Simple source code analysis
Activity lifecycle processing
First of all, let’s look at androidx.activity.Com ponentActivity, this class we mentioned many times in this series of articles, The first mention is in [back Jetpack] never lost state androidX SaveState ViewModel-SaveState analysis, interested friends can look at.
Most of the interfaces implemented have already been covered, but today we’ll take a look at LifecycleOwner
ActivityResultCaller was introduced for Activity 1.2.0-Alpha02 to unify onActivityResult. It is not discussed here
Now that the LifecycleOwner interface is implemented, the getLifecycle() method must be overridden
// androidx.activity.ComponentActivity.java
private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
@Override
public Lifecycle getLifecycle(a) {
return mLifecycleRegistry;
}
Copy the code
Lifecycle is returned as an instance of the implementation class LifecycleRegistry
The Activity operation lifecycle is handled via ReportFragment
// androidx.activity.ComponentActivity.java
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ReportFragment.injectIfNeededIn(this);
/ /...
}
// ReportFragment
public static void injectIfNeededIn(Activity activity) {
if (Build.VERSION.SDK_INT >= 29) {
// API 29 and above directly registers the correct lifecycle callbacks
activity.registerActivityLifecycleCallbacks(
new LifecycleCallbacks());
}
android.app.FragmentManager manager = activity.getFragmentManager();
if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
manager.beginTransaction().add(newReportFragment(), REPORT_FRAGMENT_TAG).commit(); manager.executePendingTransactions(); }}Copy the code
// ReportFragment.java
static void dispatch(@NonNull Activity activity, @NonNull Lifecycle.Event event) {
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); }}}private void dispatch(@NonNull Lifecycle.Event event) {
if (Build.VERSION.SDK_INT < 29) { dispatch(getActivity(), event); }}@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
dispatch(Lifecycle.Event.ON_CREATE);
}
@Override
public void onStart(a) {
super.onStart();
dispatch(Lifecycle.Event.ON_START);
}
@Override
public void onResume(a) {
super.onResume();
dispatch(Lifecycle.Event.ON_RESUME);
}
@Override
public void onPause(a) {
super.onPause();
dispatch(Lifecycle.Event.ON_PAUSE);
}
@Override
public void onStop(a) {
super.onStop();
dispatch(Lifecycle.Event.ON_STOP);
}
@Override
public void onDestroy(a) {
super.onDestroy();
dispatch(Lifecycle.Event.ON_DESTROY);
}
Copy the code
// LifecycleCallbacks
static class LifecycleCallbacks implements Application.ActivityLifecycleCallbacks {
@Override
public void onActivityPostCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
dispatch(activity, Lifecycle.Event.ON_CREATE);
}
@Override
public void onActivityPostStarted(@NonNull Activity activity) {
dispatch(activity, Lifecycle.Event.ON_START);
}
@Override
public void onActivityPostResumed(@NonNull Activity activity) {
dispatch(activity, Lifecycle.Event.ON_RESUME);
}
@Override
public void onActivityPrePaused(@NonNull Activity activity) {
dispatch(activity, Lifecycle.Event.ON_PAUSE);
}
@Override
public void onActivityPreStopped(@NonNull Activity activity) {
dispatch(activity, Lifecycle.Event.ON_STOP);
}
@Override
public void onActivityPreDestroyed(@NonNull Activity activity) {
dispatch(activity, Lifecycle.Event.ON_DESTROY);
}
/ /...
}
Copy the code
In the activity’s onCreate method, the static injectIfNeededIn() ReportFragment method is called. Internally, if the correct lifecycle callbacks are registered directly on devices with API 29 and above, the lower version handles the lifecycle callbacks by starting ReportFragment with the fragment lifecycle
Fragment life cycle processing
Inside the Fragment, each lifecycle node calls the handleLifecycleEvent method
// Fragment.java
public Fragment(a) {
initLifecycle();
}
private void initLifecycle(a) {
mLifecycleRegistry = new LifecycleRegistry(this);
}
@Override
public Lifecycle getLifecycle(a) {
return mLifecycleRegistry;
}
void performCreate(Bundle savedInstanceState) {
onCreate(savedInstanceState);
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
}
void performStart(a) {
onStart();
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
}
void performResume(a) {
onResume();
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
}
void performPause(a) {
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
onPause();
}
void performStop(a) {
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
onStop();
}
void performDestroy(a) {
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
onDestroy();
}
Copy the code
Lifecycle State size comparison
Lifecycle.State has an isAtLeast method that determines whether the current State is not less than the incoming State
// Lifecycle.State
public boolean isAtLeast(@NonNull State state) {
return compareTo(state) >= 0;
}
Copy the code
The compareTo method of enumerations actually compares the order of enumeration declarations
The order of State is DESTROYED -> INITIALIZED -> CREATED -> STARTED -> RESUMED
If the state passed in is STARTED, return true if the current state is STARTED or RESUMED, or false otherwise
The LiveData article will use this knowledge
About me
I am a Fly_with24
- The Denver nuggets
- Jane’s book
- Github