The principle of overview
Lifecycle is mainly used for monitoring the state of activities, fragments and other stative components. One of the most important functions is to remove a large number of life-cycle related callback functions in the original activities and fragments out of the View layer file. From the design point of View, Lifecycle is mainly used for monitoring the state of activities, fragments and other stative components. Make MVVM View layer file structure more clear, simple, simplify the task of View layer, make the code more clear, easy to maintain.
Lifecycle implementation listening can be implemented in two main ways, in versions below API29 it is mainly method one and in versions of API29+ it is method two.
- Like Glide, it uses a Fragment dedicated to reporting state. When this particular blank Fragment is inserted into a host Activity, it can retrieve the host’s life-cycle state changes.
- implementation
Application.ActivityLifecycleCallbacks
, listen for changes related to the lifecycle.
The general steps are as follows:
- Declare your own listening component :MyUtil implementation
LifecycleObserver interface
. - Declare life cycle callback functions with annotations:
@onlifecycleEvent (Lifecycle.event.on_create) private void fun1(){// ON_CREATE needs to do things}Copy the code
- Called in mainactivity.java:
getLifecycle().addObserver(new MyUtil());
Copy the code
Obviously in this model Lifecycle itself is only the source of an event and MyUtil, the listener that we implement ourselves, is the observer. We register our tools with Lifecycle and once Lifecycle has received notification of changes to its lifecycle, lifecycle notifies a series of observers to update:
Lifecycle itself is more like a proxy, our utility class doesn’t need to do the listening itself, so this can really be seen as a synthesis of the two observer patterns, and Lifecycle in the middle is an interface that the system provides for us to get callbacks. We just need to register our Observer. As a result, the process of analyzing Lifecycle is clearly broken down into two sub-problems:
Question 1. How does MyUtil(LifecycleObserver) listen on lifecycle?
Question 2. How does Lifecycle listen for host lifecycle changes?
Constitute a
Lifecycle is made up of:
Lifecycle
A component (Activity, Fragment) may have its own Lifecycle.LifecycleOwner
: Lifecycle holder, a component (Activity, Fragment)LifecycleObserver
: LifecycleObserver is a component whose lifecycle lifecycle needs to be observed. Lifecycle addObserver is used to register and listen to LifecycleObserver. This allows the corresponding LifecycleObserver class to get life-cycle related callbacks.Event
: life cycle callback methods, such as ON_CREATE, ON_START, etc.State
: When an Event occurs, State will change. For example, when ON_CREATE Event occurs, State will change from INITIALIZED to CREATED, as shown in the State transition diagram in [Model].INITIALIZED
: has just been initialized.CREATED
: after ON_CREATE, after ON_STOP.STARTED
: after ON_START, after ON_PAUSE.RESUMED
: ON_PAUSE after ON_RESUMEbefore.ON_DESTORYED
: has not been created or destroyed after ON_DESTROY.
model
// Corresponding state transition function
@NonNull
public State getTargetState(a) {
// Enumeration class. This identifies an event such as ON_CREATE, ON_STOP, etc.
switch (this) {
// For ON_CREATE and ON_STOP events, both correspond to CREATED states. (Both points to CREATED)
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 source code
1. addObserver(observer)
LifecycleOwner is the source of events, and both fragments and activities are lifecycleOwners. In other words, the two produce a series of life-cycle related events.
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
LifecycleOwner
Copy the code
LifecycleOwner provides a single method, and, in the ComponentActivity class, Lifecycle is used in an implementation class: mLifecycleRegistry
public interface LifecycleOwner {
@NonNull
Lifecycle getLifecycle(a);
}
private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
Copy the code
//LifecycleRegistry.java
@Override
public void addObserver(@NonNull LifecycleObserver observer) {
enforceMainThreadIfNeeded("addObserver");// Main thread assertion
State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;// If mState is destroyed, mark it as destroyed; If they are other (all valid), mark them as initialized.
ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);// Pass in a custom observer (non-observed) and state.
ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);// Try to put it into a collection of observer objects maintained by the observer (to prevent multiple registrations if none exist). If so, return value of the existing value; If no PUT exists, null is returned.
// If the same observer existed before, return;
if(previous ! =null) {
return;
}
// Retrieve lifecycleOwner object, which is usually an Activity or Fragment. Note that lifecycleOwner is referenced by WeakReference
. It is in the constructor of LifecycleRegistry that the value is injected.
//private final WeakReference<LifecycleOwner> mLifecycleOwner;
LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
// If it is empty, the object has been reclaimed and returns.
if (lifecycleOwner == null) {
// it is null we should be destroyed. Fallback quickly
return;
}
booleanisReentrance = mAddingObserverCounter ! =0 || mHandlingEvent;
State targetState = calculateTargetState(observer);
mAddingObserverCounter++;
// Number of observers being registered +1
//ENUM Comparison between classes. Equality between classes returns 0. This loop serves to append the previous lifecycle event dispatch (stickiness)
while ((statefulObserver.mState.compareTo(targetState) < 0
&& mObserverMap.contains(observer))) {
// The internal implementation of this line is: mparentstates.add (state); MParentStates is an ArrayList that stores "old" messages. For example, if you click the button to register a listener in the running state (create, start, resume), pushParentState: stateFulobServer. mState is INITIALIZED.
pushParentState(statefulObserver.mState);
INITIALIZED. The Event fetched from upFrom is "ON_CREATE", but the onCreate state is already gone.
final Event event = Event.upFrom(statefulObserver.mState);
if (event == null) {
throw new IllegalStateException("no event up from " + statefulObserver.mState);
}
// Note that the ON_CREATE and other callbacks in our instance are executed in this step (Figure 1), which updates the state and issues events. When this code is passed, stateFulobServer.mstate becomes CREATED
statefulObserver.dispatchEvent(lifecycleOwner, event);
// Corresponds to pushParentState. After pushParentState is deleted, the length of parentState is 0.
popParentState();
targetState = calculateTargetState(observer);
// StateFulobServer. mState is CREATED and targetState is updated to RESUME.
}
if(! isReentrance) {// we do sync only on the top level.
sync();
}
mAddingObserverCounter--;
}
Copy the code
And then the second round of code, which is actually similar to the first round, goes from Event to ON_CREATE to ON_START, and then sends out the ON_START Event. ON_RESUME similarly. The general process is when you add an Observer. The State FulobServer is the main one. No matter what the State of the Activity is, the initialState is INITIALIZED when it enters. Then, according to the State (State, such as CREATED), the event. upFrom function is used to fetch the Event (Event, CREATED). ON_CREATE for example), and then, statefulObserver dispatchEvent (lifecycleOwner, event); The statefulObserver is updated, and so on.
A few key expansions of the above code:
private State calculateTargetState(LifecycleObserver observer) {
//mObserverMap is line 7 of the addObserver trunk above:
//ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
// This is the only join call to the Map.
/ / remove the nearby ObserverWithState FastSafeIterableMap, comments saying is: Poor 's man LinkedHashMap
/ / LifecycleObserver as you can see, in the androidx.core.app.Com ponentActivity ComponentActivity implements this interface.
// So, the Map is an Activity with State(one State, one LifecycleEventObserver) structure:
Map.Entry<LifecycleObserver, ObserverWithState> previous = mObserverMap.ceil(observer);
// If not null, then set siblingState to mState else NULL of the object stored in PreviousState siblingState = previous ! =null ? previous.getValue().mState : null;
// If parentState is present, get State else NULL for the last parentStateState parentState = ! mParentStates.isEmpty() ? mParentStates.get(mParentStates.size() -1)
: null;
// Take the minimum value among mState, siblingState, and parentState.
return min(min(mState, siblingState), parentState);
}
//statefulObserver.dispatchEvent(lifecycleOwner, event);
void dispatchEvent(LifecycleOwner owner, Event event)
// Obtain the state according to event (ENUM). This is the same as the state graph above.
State newState = event.getTargetState();
// select the minimum state
mState = min(mState, newState);
// Update the status and respond to the callback
mLifecycleObserver.onStateChanged(owner, event);
// Set the new state
mState = newState;
}
Copy the code
2. sync()
private void sync(a) {
// Life cycle holders such as activities and fragments.
LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
// Check whether it has been collected
if (lifecycleOwner == null) {
throw new IllegalStateException("LifecycleOwner of this LifecycleRegistry is already"
+ "garbage collected. It is too late to change lifecycle state.");
}
// Loop if elements in the mObserverMap are not fully synchronized, synchronizing the state of all saved observers.
while(! isSynced()) {/ / tag if there is a new event, when moveToState is invoked, satisfy the conditions (mHandlingEvent | | mAddingObserverCounter! = 0), this property is set to true.
// The two conditions are: 1 whether the event is being processed, and 2 whether the newly added observer is being processed.
mNewEventOccurred = false;
// Compare mState to the oldest element state in the mObserverMap, and if it is smaller (the smallest is DESTROY, INITIALIZED, all the way to RESUMED), it takes a long time to update backward from the earliest element to the RESUMED map. For example, CREATED < RESUMED
if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
// backpropagation
backwardPass(lifecycleOwner);
}
Map.Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
// If no new events occur (no moveToState is triggered during this time), the latest observer is not empty, and the current component state precedes the latest component state.
For example, mState = newest. MState = CREATED, then forward propagation is triggered.
if(! mNewEventOccurred && newest ! =null
&& mState.compareTo(newest.getValue().mState) > 0) {
// Forward propagation
forwardPass(lifecycleOwner);
}
// In this loop, all Observer states are synchronized.
}
mNewEventOccurred = false;
}
private boolean isSynced(a) {
if (mObserverMap.size() == 0) {
return true;
}
State eldestObserverState = mObserverMap.eldest().getValue().mState;
State newestObserverState = mObserverMap.newest().getValue().mState;
// Check whether the latest entry is equal to the current state.
return eldestObserverState == newestObserverState && mState == newestObserverState;
}
Copy the code
/ / forwardPass similarly;
private void backwardPass(LifecycleOwner lifecycleOwner) {
/ / the iterator
Iterator<Map.Entry<LifecycleObserver, ObserverWithState>> descendingIterator =
mObserverMap.descendingIterator();
// In forwardPass:
//Iterator<Map.Entry<LifecycleObserver, ObserverWithState>> ascendingIterator =
// mObserverMap.iteratorWithAdditions();
// Iterate without a new event (moveToState triggered).
while(descendingIterator.hasNext() && ! mNewEventOccurred) { Map.Entry<LifecycleObserver, ObserverWithState> entry = descendingIterator.next(); ObserverWithState observer = entry.getValue();while ((observer.mState.compareTo(mState) > 0 && !mNewEventOccurred
&& mObserverMap.contains(entry.getKey()))) {
// Similar to the logic in addObserver, synchronization actively calls back the status of other listeners that are lagging.
Event event = Event.downFrom(observer.mState);
if (event == null) {
throw new IllegalStateException("no event down from "+ observer.mState); } pushParentState(event.getTargetState()); observer.dispatchEvent(lifecycleOwner, event); popParentState(); }}}Copy the code
3. SetCurrentState, moveToState
Methods in this category are used for external calls that will be used for the transition of state to Lifecycle. For example, we can explicitly call the setCurrentState method throughout the lifecycle of an Activity to flag (notify) the lifecycle state. Once the tag is complete, sync is triggered to synchronize all observer states.
@MainThread
public void setCurrentState(@NonNull State state) {
enforceMainThreadIfNeeded("setCurrentState");// Assert the main thread
moveToState(state);
}
/**
* Sets the current state and notifies the observers.
* <p>
* Note that if the {@codecurrentState} is the same state as the last call to this method, * Calling this method has no effect. * *@param event The event that was received
*/
public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
enforceMainThreadIfNeeded("handleLifecycleEvent");// Assert the main thread
moveToState(event.getTargetState());
}
private void moveToState(State next) {
// The same state is invalid.
if (mState == next) {
return;
}
mState = next;
// If an event is being processed, or if there is a newly added Observer (the number is not zero), then a new event is currently present.
if(mHandlingEvent || mAddingObserverCounter ! =0) {
mNewEventOccurred = true;
// we will figure out what to do on upper level.
return;
}
mHandlingEvent = true;// The tag is handling events, sort of like a lock
sync();// synchronize (forward propagation)
mHandlingEvent = false;/ / end
}
Copy the code
Listening to the
So let’s start with moveToState, which has three calls.
@Deprecated
@MainThread
public void markState(@NonNull State state) {
enforceMainThreadIfNeeded("markState");
setCurrentState(state);
}
@MainThread
public void setCurrentState(@NonNull State state) {
enforceMainThreadIfNeeded("setCurrentState");
moveToState(state);
}
public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
enforceMainThreadIfNeeded("handleLifecycleEvent");
moveToState(event.getTargetState());
}
Copy the code
MarkState has been marked as @deprecated, but we can find one call to it: onSaveInstanceState in the ComponentActivity under package Androidx.core. app still keeps this method called.
package androidx.core.app;
@CallSuper
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
mLifecycleRegistry.markState(Lifecycle.State.CREATED);//
super.onSaveInstanceState(outState);
}
Copy the code
SetCurrentState is in package Androidx. activity; ComponentActivity is referenced in:
package androidx.activity;
@CallSuper
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
Lifecycle lifecycle = getLifecycle();
if (lifecycle instanceof LifecycleRegistry) {
((LifecycleRegistry) lifecycle).setCurrentState(Lifecycle.State.CREATED);//
}
super.onSaveInstanceState(outState);
mSavedStateRegistryController.performSave(outState);
}
Copy the code
As for handleLifecycleEvent:
Obviously handleLifecycleEvent and lifecyle have a close relationship in AppcompatActivity.
For example, in the onCreate method, there are:
protected void onCreate(@Nullable Bundle savedInstanceState) {
mFragments.attachHost(null /*parent*/);
if(savedInstanceState ! =null) {
// If the Activity is being rebuilt, omit the following. }if (mPendingFragmentActivityResults == null) {
mPendingFragmentActivityResults = new SparseArrayCompat<>();
mNextCandidateRequestIndex = 0;
}
super.onCreate(savedInstanceState);
mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);// Send events
mFragments.dispatchCreate();
}
Copy the code
Whenever our Activity parent’s FragmentActivity method: onCreate is called back, it must trigger the execution of handleLifecycleEvent(), which makes listening very simple.
However, in the androidx.activity.Com ponentActivity; In, there is a very special piece of code:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mSavedStateRegistryController.performRestore(savedInstanceState);
ReportFragment.injectIfNeededIn(this);//
if(mContentLayoutId ! =0) { setContentView(mContentLayoutId); }}Copy the code
public static void injectIfNeededIn(Activity activity) {
if (Build.VERSION.SDK_INT >= 29) {
/ / On 29 + API (Android 10.0 +), we can directly register the correct lifecycle to monitor, internal will directly to realize to monitor: mActivityLifecycleCallbacks in the Activity class, add a Callback: mActivityLifecycleCallbacks.add(callback);
activity.registerActivityLifecycleCallbacks(
new LifecycleCallbacks());
}
android.app.FragmentManager manager = activity.getFragmentManager();
if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
// Notice here that we added a new ReportFragment() to the current Activity.
manager.beginTransaction().add(newReportFragment(), REPORT_FRAGMENT_TAG).commit(); manager.executePendingTransactions(); }}Copy the code
Take any Fragment lifecycle function as an observation and enter the Dispatch () method.
@Override
public void onStart(a) {
super.onStart();
dispatchStart(mProcessListener);
dispatch(Lifecycle.Event.ON_START);
}
@Override
public void onResume(a) {
super.onResume();
dispatchResume(mProcessListener);
dispatch(Lifecycle.Event.ON_RESUME);
}
@Override
public void onPause(a) {
super.onPause();
dispatch(Lifecycle.Event.ON_PAUSE);
}
Copy the code
In the Dispatch method, it is found that the activity as LifecycleOwner gets its Lifecycle event processing.
@SuppressWarnings("deprecation")
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 instanceof LifecycleRegistry) {
((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);//}}}Copy the code
LifecycleRegistryOwner is a subclass of the LifecycleOwner interface, and you can see that the return value is different. Obviously, when the Activity life cycle changes, the Fragment life cycle changes accordingly. HandleLifecycleEvent in the ReportFragment life cycle function is a very clever way to implement this function. This is very similar to Glide’s implementation, which uses a blank RequestManagerFragment.
However, in API29+, the program will walk this code:
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);
}
/ /...
}
static class LifecycleCallbacks implements Application.ActivityLifecycleCallbacks {
// There are omissions
static void registerIn(Activity activity) {
activity.registerActivityLifecycleCallbacks(new LifecycleCallbacks());
}
@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
At the same time, Api29+ models will also go to: insert a ReportFragment. In theory, through the Application. The ActivityLifecycleCallbacks callback will have to register to listen, as to why this design is not clear. But the dispatch method to dispatch the event:
private void dispatch(@NonNull Lifecycle.Event event) {
if (Build.VERSION.SDK_INT < 29) {
dispatch(getActivity(), event);//TAG}}Copy the code
It limits the listening generated by the Fragment lifecycle callback to being dispatched only when Api<29, so no two dispatches occur. The dispatch at the TAG is a static method, and notice that THE DISPATCH from API29+ is called directly from that static method.
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); }}}// The call in API29 follows the static method above.
@Override
public void onActivityPostStarted(@NonNull Activity activity) {
dispatch(activity, Lifecycle.Event.ON_START);
}
Copy the code
Whether API29 following through fragments to monitor or API29 above, through the Application. The ActivityLifecycleCallbacks monitor, walk is lifecycle. HandleLifecycleEvent () method. This is why handleLifecycleEvent was mentioned above with a large number of calls:
other
1. Application.ActivityLifecycleCallbacks
This interface contains a lot of the callback function, and the three different to the callback function in the daily development, here is more detailed, divided into three groups, each group and distinguish between pre and post, plus a onActivitySaveInstanceState, whenever the Activity life cycle change occurs, The callback function is called back to and the parameter is the changed Activity. We can customize a class implements this interface, and then enclosing registerActivityLifecycleCallbacks (callbacks); Just register. This class also allows for more flexible Activity instance control. Most of the events are handled in the POST section, not the Pre.
@Override public void onActivityResumed(@NonNull Activity activity) {}@Override public void onActivityPostResumed(@NonNull Activity activity) { dispatch(activity, Lifecycle.Event.ON_RESUME);// Issue events to listeners (MyUtils class, etc.) } Copy the code
conclusion
Starting with listening, in versions later than API29, a ReportFragment is added to the Activity. When the lifecycle of the Fragment changes, the time will be sent to update the lifecycle. Lifecycle notifies the LifecycleObserver of Lifecycle updates uniformly; While API29 +, can directly through the monitoring Application. ActivityLifecycleCallbacks interface, to obtain the Activity state, at the same time also can insert ReportFragment, However, dispatch in the life cycle of the Fragment reporting the state will not take effect. Both the Fragment and the Activity add a listener and output before and after onStop. The order of callbacks in the two methods (API29+ and API29 below) is also different.
Attachment: part of the official document
Handle ON_STOP events (Google links may not open)
1. Handle the ON_STOP event
If Lifecycle is an AppCompatActivity or Fragment, then calling onSaveInstanceState() for AppCompatActivity or Fragment, Lifecycle will change the state to CREATED and an ON_STOP event will be dispatched.
After saving the state of a Fragment or appactivity with onSaveInstanceState(), the interface is considered immutable until ON_START is called. If you try to modify the interface after saving the state, it is likely that the application’s navigational state will be inconsistent, so when the application runs FragmentTransaction after saving the state, the FragmentManager will throw an exception. ** For more details, see Commit ().
LiveData itself prevents this extreme situation by avoiding calling its observer when its Lifecycle is not at least STARTED. Behind the scenes, it calls isAtLeast() before deciding to call its observer.
Unfortunately, the onStop() method for AppCompatActivity will be called after onSaveInstanceState(), which leaves a gap that doesn’t allow the interface state to change, but Lifecycle hasn’t moved to the CREATED state.
To prevent this, the Lifecycle class in Beta2 and earlier marks the state as CREATED without dispatching events, so that code that checks the current state will get the actual value even if the event is not dispatched (until the system calls onStop()).
Unfortunately, there are two main problems with this solution:
- At API 23 and below, the Android system actually saves the state of an Activity even if part of it is overwritten by another Activity. In other words, the Android system calls
onSaveInstanceState()
, but not necessarily calledonStop()
. This can result in long intervals in which the observer still perceives the life cycle to be active, although its interface state cannot be modified. - Any to
LiveData
Classes that expose similar behavior must be implemented byLifecycle
versionbeta 2
And lower versions of the solution.
Note: To simplify this process and make it more compatible with earlier versions, from 1.0.0-rC1 Lifecycle object is marked as CREATED and ON_STOP is dispatched when onSaveInstanceState() is called, Instead of waiting for the onStop() method to be called. This is unlikely to affect your code, but you need to be aware of it because it does not correspond to the order of calls in API 26 and lower Activity classes.
2. Best practices for lifecycle aware components
- Keep interface controllers (activities and fragments) as lean as possible. Instead of trying to get their own data, they should do so using the ViewModel and observe the LiveData object to reflect changes into the view.
- Try to write data-driven interfaces where the interface controller’s responsibility is to update the view as the data changes, or to notify the ViewModel of user actions.
- Put the data logic in the ViewModel class. The ViewModel should act as a connector between the interface controller and the rest of the application. Note, however, that the ViewModel is not responsible for fetching data (for example, from the network). However, the ViewModel should call the corresponding component to get the data and then feed the results to the interface controller.
- Use data binding to maintain a clean interface between views and interface controllers. In this way, you can make your views more declarative and minimize the amount of updating code that needs to be written in activities and fragments. If you prefer to do this in the Java programming language, use a library such as Butter Knife to avoid boilerplate code and achieve better abstraction.
- If the interface is complex, consider creating a Presenter class to handle changes to the interface. This can be a daunting task, but doing so makes interface components easier to test.
- To avoid the
ViewModel
Referenced in theView
或Activity
The context. ifViewModel
Existing longer than an Activity (in the case of a configuration change), the Activity will leak and not be properly disposed of by the garbage collector. - Use Kotlin coroutines to manage long-running tasks and other operations that can run asynchronously.