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 theViewModelReferenced in theViewActivityThe context. ifViewModelExisting 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.