I. Definition and function
1.1, definitions,
Lifecycle is a component that senses the Lifecycle of an Activity or Fragment. Lifecycle is an object that represents the Lifecycle and state of android
1.2,
Lifecycle can effectively avoid memory leaks and solve common problems of the Android Lifecycle. LivecycleOwner is used to connect objects with a Lifecycle. For example, activity,fragment LivecycleObserver is used to observe and check LifecycleOwner
1.3, usage,
How do we handle doing different code operations for different life cycles without Lifecycle?
Case 1: When using baidu Map SDK, we need to bind the map control’s life cycle to the Activity or Fragment’s life cycle
class MapActivity : AppCompatActivity {
private lateinit var mMapView:MapView
override fun onCreate(savedInstanceState:Bundle){
// Omit other code here
mMapView = findViewById(R.id.bmapView)
}
override fun onResume(a) {
super.onResume()
mMapView.onResume()
}
override fun onPause(a) {
super.onPause()
mMapView.onPause()
}
override fun onDestroy(a) {
super.onDestroy()
mMapView.onDestroy()
}
}
Copy the code
Case 2: Adding statistics code to each lifecycle of an Activity or Fragment when using Friendship statistics
class BaseActivity : AppCompatActivity {
override fun onResume(a) {
super.onResume()
MobclickAgent.onPageStart(javaClass.simpleName)
MobclickAgent.onResume(this)}override fun onPause(a) {
super.onPause()
MobclickAgent.onPageEnd(javaClass.simpleName)
MobclickAgent.onPause(this)}}class BaseFragment : Fragment {
override fun onResume(a) {
super.onResume()
MobclickAgent.onPageStart(javaClass.simpleName)
}
override fun onPause(a) {
super.onPause()
MobclickAgent.onPageEnd(javaClass.simpleName)
}
}
Copy the code
If there is a problem with these cases, there is nothing wrong with writing this way. All the functions can be implemented, but once you have too many operations that need to be bound in the life cycle, it becomes messy and does not conform to the single responsibility principle. It would be simpler and more elegant to encapsulate different functions in different classes.
Lifecycle will be packaged in case 2:
class UMengLifecycle private constructor(private val context: Context,private val className:String):LifecycleEventObserver {
private val isFragment: Boolean
companion object {
@JvmStatic
fun with(fragment: Fragment) {
LifecycleUtil(fragment.requireContext(),fragment.javaClass.simpleName)
}
@JvmStatic
fun with(activity: Activity) {
LifecycleUtil(activity,activity.javaClass.simpleName)
}
@JvmStatic
fun with(activity: FragmentActivity) {
LifecycleUtil(activity,activity.javaClass.simpleName)
}
}
init {
when(context){
is FragmentActivity->{
isFragment = false
context.lifecycle.addObserver(this)}is Fragment->{
isFragment = true
context.lifecycle.addObserver(this)}else -> throw Throwable("not support this context type")}}override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
when (event) {
Lifecycle.Event.ON_RESUME -> {
MobclickAgent.onPageStart(className)
if(! isFragment) { MobclickAgent.onResume(context) } } Lifecycle.Event.ON_PAUSE -> { MobclickAgent.onPageEnd(className)if(! isFragment) { MobclickAgent.onPause(context) } } } } }Copy the code
How is it used in an Activity?
class BaseActivity: AppCompatActivity {
public BaseActivity(){
LifecycleUtil.with(this); }}Copy the code
How is it used in fragments?
class BaseFragment: Fragment {
override fun onAttach(context:Context){ LifecycleUtil.with(context); }}Copy the code
Why can’t fragments be used in constructors?
Now let’s look at when Lifecycle LifecycleRegistry is initialized in activities and fragments
/ / path: androidx/activity/ComponentActivity Java
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
LifecycleOwner.ViewModelStoreOwner.SavedStateRegistryOwner.OnBackPressedDispatcherOwner {
private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
}
Copy the code
/ / path: androidx fragments/app/fragments, Java
public class Fragment implements ComponentCallbacks.OnCreateContextMenuListener.LifecycleOwner.ViewModelStoreOwner.SavedStateRegistryOwner {
LifecycleRegistry mLifecycleRegistry;
public Fragment(a) {
initLifecycle();
}
private void initLifecycle(a) {
mLifecycleRegistry = new LifecycleRegistry(this);
/ /...}}Copy the code
In an Activity, LifecycleRegistry is a member variable that can be called in the constructor, whereas in a Fragment, LifecycleRegistry will not be initialized until the constructor completes. So if used in the Fragment constructor it will cause crash, which is called in onAttach.
Best practices:
- 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.
Use cases:
- Toggle between coarse-grained and fine-grained position updates. Use lifecycle aware components to enable fine-grained location updates when the location application is visible and switch to coarse-grained updates when the application is in the background. With the life-cycle aware component LiveData, the application can automatically update the interface when the user’s usage location changes.
- Stop and start video buffering. Use lifecycle aware components to start video buffering as soon as possible, but delay playback until the application is fully started. In addition, you can terminate buffering using life-cycle-aware components after applying destruction.
- Start and stop network connections. Life-cycle aware components enable real-time updates (streaming) of network data when the application is in the foreground and automatically pauses when the application is in the background.
- Pause and resume animation drawable resources. Life-cycle-aware components allow you to pause animatable drawable resources while the application is in the background and restore drawable resources after the application is in the foreground.
The observed and the observer
Lifecycle is implemented through the observer pattern to monitor the Lifecycle of an Activity/Fragment.
2.1 Observed
In the Activity, the LifecycleOwner interface is implemented in the ComponentActivity class, which implements getLifecycle
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
LifecycleOwner.ViewModelStoreOwner.SavedStateRegistryOwner.OnBackPressedDispatcherOwner {
@Override
public Lifecycle getLifecycle(a) {
returnmLifecycleRegistry; }}Copy the code
In Fragment, the LifecycleOwner interface is implemented, and getLifecycle is also implemented
public class Fragment implements ComponentCallbacks.OnCreateContextMenuListener.LifecycleOwner.ViewModelStoreOwner.SavedStateRegistryOwner {
@NonNull
public Lifecycle getLifecycle(a) {
returnmLifecycleRegistry; }}Copy the code
You don’t need to implement your own interface when using activities or fragments
2.2 Observer
Observing is implemented by implementing the LifecycleObserver interface, but the LifecycleObserver interface is an empty interface
public interface LifecycleObserver {
// There is no implementation interface
}
Copy the code
You can use annotations to receive the observed event send
public class BasePresenter<T extends IBaseView> implements LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
void onCreate(LifecycleOwner owner) {}@OnLifecycleEvent(Lifecycle.Event.ON_START)
void onStart(LifecycleOwner owner) {}@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
void onStop(LifecycleOwner owner) {}@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
void onResume(LifecycleOwner owner) {}@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
void onPause(LifecycleOwner owner) {}@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
void onDestroy(LifecycleOwner owner) {}@OnLifecycleEvent(Lifecycle.Event.ON_ANY)
void onAny(LifecycleOwner owner) {}}Copy the code
Several commonly used interfaces are defined based on the LifecycleObserver:
-
LifecycleEventObserver
void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event); Copy the code
-
FullLifecycleObserver
void onCreate(LifecycleOwner owner); void onStart(LifecycleOwner owner); void onResume(LifecycleOwner owner); void onPause(LifecycleOwner owner); void onStop(LifecycleOwner owner); void onDestroy(LifecycleOwner owner); Copy the code
2.3, subscription
Use getLifecycle().addobServer (XXX) in your Activity or Fragment.
Observed. AddObserver (Observer)
Iii. Core principles
We will start with getLifecycle().addobServer (XXX) as a step by step entry to view the source code:
GetLifecycle () returns a LifecycleRegistry class:
public class LifecycleRegistry extends Lifecycle {
// To store the observer and the current state
// Implements a HashMap single linked list, but value is a double linked list wrapper
private FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap =
new FastSafeIterableMap<>();
// Weakly referenced LifecycleOwner to facilitate tag collection when an Activity or Fragment is released
// will be initialized in the constructor
private final WeakReference<LifecycleOwner> mLifecycleOwner;
@Override
public void addObserver(@NonNull LifecycleObserver observer) {
State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
// Wrapping the LifecycleObserver object converts the LifecycleObserver into a LifecycleEventObserver object
ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
// Save to the mObserverMap object
ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
if(previous ! =null) {
return;
}
LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
if (lifecycleOwner == null) {
// it is null we should be destroyed. Fallback quickly
return;
}
booleanisReentrance = mAddingObserverCounter ! =0 || mHandlingEvent;
// Get the page state at the time of the current addObserver, since addObserver is not necessarily executed in the onCreate method
State targetState = calculateTargetState(observer);
mAddingObserverCounter++;
// stateFulobServer. mState is smaller than targetState
while ((statefulObserver.mState.compareTo(targetState) < 0
&& mObserverMap.contains(observer))) {
pushParentState(statefulObserver.mState);
// Trigger Event Event distribution to update the mState state
statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
popParentState();
// mState / subling may have been changed recalculate
targetState = calculateTargetState(observer);
}
if(! isReentrance) {// we do sync only on the top level.sync(); } mAddingObserverCounter--; }}Copy the code
Sync () : synchronizes the current status
private void sync() { LifecycleOwner lifecycleOwner = mLifecycleOwner.get(); if (lifecycleOwner == null) { throw new IllegalStateException("LifecycleOwner of this LifecycleRegistry is already" + "garbage collected. It is too late to change lifecycle state."); } // mState changes when ReportFragment is being distributed, isSynced()=false while (! isSynced()) { mNewEventOccurred = false; // no need to check eldest for nullability, Because isSynced does it for us.if (mState.compareTo(mobservermap.eldest ().getValue().mstate) < 0) {// pass backwards backwardPass(lifecycleOwner); } Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest(); if (! mNewEventOccurred && newest ! = null &&mstate.com pareTo(newest.getValue().mstate) > 0) {// Pass forwardPass(lifecycleOwner); } } mNewEventOccurred = false; }Copy the code
ForwardPass: traverses mStart to mCurrent in the mObserverMap from the state when it was first added to the mObserverMap to the current Activity or Fragment state
BackwardPass: Passes backwards, traverses the mObserverMap mEnd to mStart from the state of the last member of the mObserverMap to the state of the last LifecycleObserver
// Pass private void forwardPass(LifecycleOwner LifecycleOwner) {Iterator<Entry<LifecycleObserver, ObserverWithState>> ascendingIterator = mObserverMap.iteratorWithAdditions(); / / the State enumeration sequentially go again, until two in the same State while (ascendingIterator. HasNext () &&! mNewEventOccurred) { Entry<LifecycleObserver, ObserverWithState> entry = ascendingIterator.next(); ObserverWithState observer = entry.getValue(); while ((observer.mState.compareTo(mState) < 0 && ! mNewEventOccurred && mObserverMap.contains(entry.getKey()))) { pushParentState(observer.mState); observer.dispatchEvent(lifecycleOwner, upEvent(observer.mState)); popParentState(); }}} private void backwardPass(LifecycleOwner LifecycleOwner) {Iterator<Entry<LifecycleObserver, ObserverWithState>> descendingIterator = mObserverMap.descendingIterator(); / / the State enumeration sequentially go again, until two in the same State while (descendingIterator. HasNext () &&! mNewEventOccurred) { 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); pushParentState(getStateAfter(event)); observer.dispatchEvent(lifecycleOwner, event); popParentState(); }}}Copy the code
Looking at the observer registration process above, how does the observed inform the observer of life cycle changes?
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
LifecycleOwner.ViewModelStoreOwner.SavedStateRegistryOwner.OnBackPressedDispatcherOwner {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mSavedStateRegistryController.performRestore(savedInstanceState);
// Register a ReportFragment to observe the lifecycle
ReportFragment.injectIfNeededIn(this);
if(mContentLayoutId ! =0) { setContentView(mContentLayoutId); }}}Copy the code
As an empty Fragment, the ReportFragment observes the life cycle of activities and fragments and distributes notifications to them
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();
// Hopefully, we are the first to make a transaction.manager.executePendingTransactions(); }}Copy the code
Look at the ReportFragment lifecycle:
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
dispatchCreate(mProcessListener);
dispatch(Lifecycle.Event.ON_CREATE);
}
@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);
}
@Override
public void onStop(a) {
super.onStop();
dispatch(Lifecycle.Event.ON_STOP);
}
@Override
public void onDestroy(a) {
super.onDestroy();
dispatch(Lifecycle.Event.ON_DESTROY);
// just want to be sure that we won't leak reference to an activity
mProcessListener = null;
}
Copy the code
Both have the dispatch(Event) method, and let’s look at this method:
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
The handleLifecycleEvent(Event) method is called. LifecycleOwner is implemented in the Activity so the handleLifecycleEvent of LifecycleRegistry is called
LifecycleRegistry handleLifecycleEvent:
public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
State next = getStateAfter(event);
moveToState(next);
}
Copy the code
GetStateAfter (event) gets the next state type:
static State getStateAfter(Event event) {
switch (event) {
case ON_CREATE:
case ON_STOP:
return CREATED;
case ON_START:
case ON_PAUSE:
return STARTED;
case ON_RESUME:
return RESUMED;
case ON_DESTROY:
return DESTROYED;
case ON_ANY:
break;
}
throw new IllegalArgumentException("Unexpected event value " + event);
}
Copy the code
MoveToState (event) moves to the next state:
private void moveToState(State next) {
if (mState == next) {
return;
}
mState = next;
if(mHandlingEvent || mAddingObserverCounter ! =0) {
mNewEventOccurred = true;
// we will figure out what to do on upper level.
return;
}
mHandlingEvent = true;
// Use this method to synchronize the status, back to backwardPass or forwardPass
sync();
mHandlingEvent = false;
}
Copy the code
Both forwardPass and backwardPass in sync() call the observer.dispatchEvent method to distribute state
The dispatchEvent method is in the Class ObserverWithState class
void dispatchEvent(LifecycleOwner owner, Event event) {
State newState = getStateAfter(event);
mState = min(mState, newState);
mLifecycleObserver.onStateChanged(owner, event);
mState = newState;
}
Copy the code
Through mLifecycleObserver. OnStateChanged (the owner, the event); The callback is distributed to the interface implementation class that implements onStateChanged event, such as LifecycleEventObserver. If there is no implementation class that inherits LifecycleEventObserver, Lifecycling would build a ReflectiveGenericLifecycleObserver class, through reflection OnLifecycleEvent annotations registration method, and then call the invoke methods by using the method of corresponding implementation lifecycle callback.