The most complete network: Jetpack AAC (-) analysis

Original link: https://juejin.cn/post/689387...

Android 35 content

Jetpack5 contents

Lifecycle 1 content

Android architecture component 5 contents

1, Introduction to Android Jetpack

1.1 what is jetpack

The official definition is as follows:

Jetpack is a suite composed of multiple libraries, which can help developers follow best practices, reduce template code, and write code that can run consistently in various Android versions and devices, so that developers can focus on writing important code.

JetPack is more of a concept and attitude. It is a collection of SDK / development specifications that are not included in the Android Framework SDK developed by Google, but are necessary / recommended for Android development. It is equivalent to Google reorganizing its Android ecosystem and establishing the general direction of Android development in the future.

Using Jetpack has the following benefits:

  • Following best practices, Android Jetpack components are built with the latest design methods, have backward compatibility, and can reduce crashes and memory leaks.
  • By eliminating boilerplate code, Android Jetpack can manage a variety of cumbersome activities (such as background tasks, navigation and Lifecycle Management), so that you can focus on building excellent applications.
  • Reduce inconsistencies, and these libraries work in a consistent manner across Android versions and devices, helping you reduce complexity.

Jetpack originally means jet backpack. Android goes straight to the sky after carrying jetpack, which is very vivid~

In other words, Jetpack is a tool set to help developers develop applications efficiently. So what does this tool include?

1.2 Jetpack classification

The classification is shown in the following figure (this figure can no longer be found on the official website):

The Android Jetpack component covers the following four aspects: Architecture, Foundation, Behavior, and UI.

The real essence is Architecture, the full name is Android Architecture Component (AAC), that is, Android architecture component.

It includes successful Lifecycle, LiveData and ViewModel. It is also the best framework tool for us to use MVVM mode. It can be used in combination or alone.

The above is basically the introduction of the official website. Our main goal is to master the components of AAC, deeply understand and then apply it to the MVVM architecture.

For example, the focus of learning Jetpack is AAC. This article starts from the basic Lifecycle.

2, Lifecycle

Lifecycle, as its name suggests, is used to help developers manage the life cycle of activities and fragments. It is the basis of LiveData and ViewModel. Here's why and how to use lifecycle.

2.1 before lifecycle

There is an example in the official document to illustrate how to use Lifecycle management before using Lifecycle:

Suppose we have an Activity that displays the location of the device on the screen. Common implementations may be as follows:

    class MyLocationListener {       
 public MyLocationListener(Context context, Callback callback) {           
 // ...       
 }  
      
void start() {           
 //  Connection system location service        
 }       

 void stop() {         
   //  Disconnect system location service
      }   
 }   

 class MyActivity extends AppCompatActivity {       
 private MyLocationListener myLocationListener;       

 @Override      
  public void onCreate(...) {           
 myLocationListener = new MyLocationListener(this, (location) -> {               
 //  Update UI
       });    
    }       

 @Override        
public void onStart() {     
       super.onStart();         
   myLocationListener.start();        
    //  Manage other components that need to respond to the activity lifecycle
       }       

 @Override     
   public void onStop() {       
     super.onStop();        
    myLocationListener.stop();    
        //  Manage other components that need to respond to the activity lifecycle      
   }  
  }    

Although this example looks ok, in a real application, there will eventually be too many calls to the management interface and other components in response to the current state of the life cycle. Managing multiple components places a lot of code in lifecycle methods such as onStart() and onStop(), which makes them difficult to maintain.

In addition, there is no guarantee that the component will start mylocationlistener before the Activity or Fragment stops. This is especially true when we need to perform long-running operations, such as some configuration check in onStart(). In this case, the onStop() method of myLocationListener is called before onStart (), which makes the component remaining longer than the time required, resulting in internal leakage. As follows:

    class MyActivity extends AppCompatActivity {    
    private MyLocationListener myLocationListener;       

 public void onCreate(...) {        
    myLocationListener = new MyLocationListener(this, location -> {       
         //  to update   UI
            });       
 }
      
  @Override      
  public void onStart() {      
      super.onStart();         
   Util.checkUserStatus(result -> {            
    //If checkUserStatus takes a long time and calls back after the activity stops, then the stop() method cannot be used after myLocationListener is started,             
    //Because myLocationListener holds activity, it will cause memory leakage.               
  if (result) {           
         myLocationListener.start();            
    }         
   });      
  }      

  @Override       
 public void onStop() {         
   super.onStop();       
     myLocationListener.stop();     
   }    
}    

There are two problem points:

  • There is a lot of code to manage components in the life cycle of activity, which is difficult to maintain.
  • There is no guarantee that the component will not start after the Activity/Fragment is stopped

Lifecycle library can solve these problems in an elastic and isolated manner.

2.2 use of lifecycle

Lifecycle is a library and also contains a class like lifecycle. Lifecycle class is used to store information about the lifecycle state of components (such as Activity or Fragment) and allow other objects to observe this state.

2.2.1 introducing dependencies

1. Non Android X project   introduce:

implementation "android.arch.lifecycle:extensions:1.1.1"

Adding this sentence depends on the following Library:

2. Android X project   introduce:

If the project already depends on Android X:

implementation 'androidx.appcompat:appcompat:1.2.0'

Then we can use the Lifecycle library, because appcompat depends on Android x.fragment, while Android x.fragment depends on ViewModel and LiveData, and LiveData internally depends on Lifecycle.

If you want to introduce dependencies separately, see the following:

Add google() code base to build.gradle in the root directory of the project, and then introduce dependencies to build.gradle of app. The official dependencies are as follows:

//Of the root directory   build.gradle  
   repositories {       
 google()       
 ...   
 }

//build.gradle of app  
    dependencies {       
 def lifecycle_version = "2.2.0"      
  def arch_version = "2.1.0"      

  // ViewModel    
    implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version" 
  // LiveData     
    implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"       
 //  Only Lifecycles   (without)   ViewModel   or   LiveData)        
 implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"  
 
 // Saved state module for ViewModel       
 implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"       
 
//  lifecycle annotation processor       
  annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"       
 //  replace  -  If you use Java 8, replace the above lifecycle compiler with this one  
 implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" 
//The following are introduced as needed        
 //  Optional  -  Help implement lifecycle owner of Service        
 implementation "androidx.lifecycle:lifecycle-service:$lifecycle_version"      
  //  Optional  -  Processlifecycle owner to the entire   app process   Provide a lifecycle
  implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"    
    //  Optional  -  ReactiveStreams   support   for   LiveData      
   implementation "androidx.lifecycle:lifecycle-reactivestreams:$lifecycle_version"      
  //  Optional  -  Test   helpers   for   LiveData       
  testImplementation "androidx.arch.core:core-testing:$arch_version"  
  }    

It seems that there are many. In fact, if you only use Lifecycle, you only need to introduce Lifecycle runtime. However, they are usually used together with ViewModel and LiveData, so Lifecycle ViewModel and Lifecycle LiveData will also be introduced.

In addition, lifecycle process provides a lifecycle for the entire app process, which will also be mentioned in the meeting.

2.2.2 application method

Lifecycle is simple to use:

  • 1. The Lifecycle owner uses getLifecycle() to obtain the Lifecycle instance, and then uses addObserve() to add the observer;
  • 2. The observer implements LifecycleObserver. The onllifecycle event annotation is used to focus on the corresponding life cycle. When the life cycle is triggered, the corresponding method will be executed;

2.2.2.1 basic use

In Activity (or Fragment), the general usage is as follows:

public class LifecycleTestActivity extends AppCompatActivity {  

  private String TAG = "Lifecycle_Test";   
 @Override  
  protected void onCreate(Bundle savedInstanceState) {      
  super.onCreate(savedInstanceState);       
 setContentView(R.layout.activity_lifecycle_test);      
  //Lifecycle   life cycle
getLifecycle().addObserver(new MyObserver());     
   Log.i(TAG, "onCreate: ");   
 }  
  @Override 
   protected void onResume() {      
  super.onResume();       
 Log.i(TAG, "onResume: ");    
}
    @Override   
 protected void onPause() {     
   super.onPause();     
   Log.i(TAG, "onPause: ");   
 }
}

Activity (or Fragment) is the owner of the life cycle. The life cycle object is obtained through the getLifecycle() method. The life cycle object uses the addObserver method to add an observer to itself, that is, the MyObserver object. When the Lifecycle changes, MyObserver can perceive it.

How does MyObserver use the lifecycle? Take a look at the implementation of MyObserver:

public class MyObserver implements LifecycleObserver {  

  private String TAG = "Lifecycle_Test";       

 @OnLifecycleEvent(value = Lifecycle.Event.ON_RESUME)  
  public void connect(){   
 Log.i(TAG, "connect: ");  
  }  

 @OnLifecycleEvent(value = Lifecycle.Event.ON_PAUSE)   
 public void disConnect(){       
 Log.i(TAG, "disConnect: ");   
 }
}

Firstly, MyObserver implements the interface LifecycleObserver, which is used to mark a class as a lifecycle observer. Then @ onllifecycle event annotation is added to connectListener() and disconnectListener(), and the value is lifecycle.event.on respectively_ RESUME,Lifecycle.Event.ON_PAUSE, the effect is: connectListener() will be on_ When resume is executed, disconnectListener() will be on_ Execute when pause.

We open lifecycle test activity and exit. The log is printed as follows:

2020-11-09 17:25:40.601 4822-4822/com.hfy.androidlearning I/Lifecycle_Test: onCreate: 

2020-11-09 17:25:40.605 4822-4822/com.hfy.androidlearning I/Lifecycle_Test: onResume: 
2020-11-09 17:25:40.605 4822-4822/com.hfy.androidlearning I/Lifecycle_Test: connect: 

2020-11-09 17:25:51.841 4822-4822/com.hfy.androidlearning I/Lifecycle_Test: disConnect: 
2020-11-09 17:25:51.841 4822-4822/com.hfy.androidlearning I/Lifecycle_Test: onPause: 

It can be seen that the method of MyObserver is indeed called when the corresponding concerned life cycle is triggered. Of course, the value in the annotation can also be written as any other life cycle you are concerned about, such as Lifecycle.Event.ON_DESTROY.

2.2.2.2 use in MVP architecture

If it is   In MVP architecture, the presenter can be regarded as an observer:

public class LifecycleTestActivity extends AppCompatActivity implements IView {   
 private String TAG = "Lifecycle_Test";  

  @Override    
protected void onCreate(Bundle savedInstanceState) {      
  super.onCreate(savedInstanceState);       
 setContentView(R.layout.activity_lifecycle_test);     
   //Lifecycle   life cycle
//        getLifecycle().addObserver(new MyObserver());       

 //Using Lifecycle in MVP    
       getLifecycle().addObserver(new MyPresenter(this));     
       Log.i(TAG, "onCreate: "); 
   }   

 @Override    protected void onResume() {   
     super.onResume();   
     Log.i(TAG, "onResume: ");   
 }    

@Override  
 protected void onPause() {       
 super.onPause();      
  Log.i(TAG, "onPause: ");   
 }    

@Override    
public void showView() {}    
@Override    public void hideView() {}
}

//Presenter
class MyPresenter implements LifecycleObserver {  
  private static final String TAG = "Lifecycle_Test";   
 private final IView mView;   

 public MyPresenter(IView view) {mView = view;}   

 @OnLifecycleEvent(value = Lifecycle.Event.ON_START)   
 private void getDataOnStart(LifecycleOwner owner){
        Log.i(TAG, "getDataOnStart: ");
                
        Util.checkUserStatus(result -> {
                //checkUserStatus is a time-consuming operation. Check the current lifecycle status after callback
                if (owner.getLifecycle().getCurrentState().isAtLeast(STARTED)) {
                 start();
                    mView.showView();
                }
            });
}
@OnLifecycleEvent(value = Lifecycle.Event.ON_STOP)    
private void hideDataOnStop(){
        Log.i(TAG, "hideDataOnStop: ");
        stop();
        mView.hideView();
    }
}

//IView
interface IView {    
      void showView();    
      void hideView();
}

Here, let the Presenter implement the LifecycleObserver interface, annotate the life cycle to be triggered on the method, and finally add it to the Lifecycle as an observer in the Activity.

What are the benefits of doing so? When the Activity lifecycle changes, MyPresenter can sense and execute the method without calling MyPresenter in multiple lifecycle methods of MainActivity.

  • All method call operations are managed by the component itself: the Presenter class automatically senses the life cycle. If you need to use this Presenter in other activities / fragments, you just need to add it as an observer.
  • Let each component store its own logic, reduce the code in Activity/Fragment, and make it easier to manage;

——The first problem mentioned above has been solved.

In addition, it is noted that after the time-consuming verification callback in getDataOnStart(), the current life cycle state is checked: the start() method will not be executed until it is at least in the STARTED state, that is, it is guaranteed that the start() method will not be executed after the Activity stops;

——The second problem mentioned above has also been solved.

2.2.3 customize lifecycle owner

When you call getLifecycle() in Activity, you can get the Lifecycle instance. Where is getLifecycle() defined? It is the interface lifecycle owner, Gu Minglai, and the lifecycle owner:

/** 
* Lifecycle owner  
* Lifecycle events can be   Custom components   be used for   Handle changes in lifecycle events without writing any code in Activity/Fragmen  
*/
public interface LifecycleOwner {
    @NonNull
    Lifecycle getLifecycle();
}

Support Library 26.1.0 and above, Android x Fragment and Activity have implemented the lifecycle owner interface, so we can directly use getLifecycle() in the Activity.

If you have a custom class and want to make it a Lifecycle owner, you can use the Lifecycle registry class, which is the implementation class of Lifecycle, but you need to forward events to this class:

    public class MyActivity extends Activity implements LifecycleOwner {
        private LifecycleRegistry lifecycleRegistry;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);

            lifecycleRegistry = new LifecycleRegistry(this);
            lifecycleRegistry.markState(Lifecycle.State.CREATED);
        }       
        @Override       
public void onStart() { 
           super.onStart();
            lifecycleRegistry.markState(Lifecycle.State.STARTED);
        }        
@NonNull        
@Override        
public Lifecycle getLifecycle() {           
 return lifecycleRegistry;       
 }    
}

MyActivity implements the lifecycle owner, and getLifecycle() returns the lifecycle registry instance. The lifecycleRegistry instance is created in onCreate, and the markState() method is called in each life cycle to complete the delivery of life cycle events. This completes the customization of LifecycleOwner, that is, MyActivity becomes LifecycleOwner, and then it can be used with the components that implement LifecycleObserver.

In addition, the observer method can accept a parameter lifecycle owner, which can be used to obtain the current state or continue to add observers. If the annotation is ON_ANY can also receive an Event to distinguish which Event it is. As follows:

    class TestObserver implements LifecycleObserver { 
       @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) 
       void onCreated(LifecycleOwner owner) {
//            owner.getLifecycle().addObserver(anotherObserver);
//            owner.getLifecycle().getCurrentState();        
}        
@OnLifecycleEvent(Lifecycle.Event.ON_ANY)        
void onAny(LifecycleOwner owner, Lifecycle.Event event) {
//            event.name()       
   }  
  }

2.3 Application lifecycle processlifecycle owner

The previous judgment of the App entering the front and background is through the registeractivitylifecycle callbacks (callback) method, and then count with a global variable in the callback, add 1 in onActivityStarted() and subtract 1 in onActivityStopped() to judge the front and rear switching.

Using processlifecycle owner, you can directly obtain the application front and background switching status. (remember to introduce the lifecycle process dependency first)

The usage method is similar to that in Activity, except that processlifecycle owner. Get() is used to obtain processlifecycle owner. The code is as follows:

public class MyApplication extends Application {    
@Override
    public void onCreate() {
        super.onCreate(); 

//Register App lifecycle watcher
        ProcessLifecycleOwner.get().getLifecycle().addObserver(new ApplicationLifecycleObserver());    }        

/**    
 * Application Life cycle observation provides the life cycle of the whole application process      
*
     * Lifecycle.Event.ON_CREATE It will only be distributed once, Lifecycle.Event.ON_DESTROY will not be distributed.      
*
     * When the first Activity enters, processlifecycle owner will dispatch Lifecycle.Event.ON_START, Lifecycle.Event.ON_RESUME.       
* Lifecycle.Event.ON_PAUSE, Lifecycle.Event.ON_STOP, the distribution will be delayed after the last Activit exits. If the activity is destroyed and recreated due to a configuration change, this delay is sufficient to ensure that the processlifecycle owner does not send any events.      
*
     * Function: monitor the application to enter the foreground or background      
*/    
private static class ApplicationLifecycleObserver implements LifecycleObserver {        
@OnLifecycleEvent(Lifecycle.Event.ON_START)
        private void onAppForeground() {
            Log.w(TAG, "ApplicationObserver: app moved to foreground");
        }       

   @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
        private void onAppBackground() { 
           Log.w(TAG, "ApplicationObserver: app moved to background"); 
       }    
  }
}

It's really simple to see, which is almost the same as the Lifecycle usage of the previous Activity, and it's elegant to use processlifecycle owner. The Lifecycle distribution logic is described in the notes.

3, Source code analysis

The use of Lifecycle is very simple. The next step is to analyze the principle and source code of Lifecycle.

We can guess the principle first: when the lifecycle owner (such as Activity) changes the lifecycle state (that is, when the lifecycle method is executed), it traverses the observers and obtains the annotation on each observer's method. If the annotation is @ onllifecycle event and the value is consistent with the lifecycle state, then this method is executed. Is that a reasonable guess? Let's have a look.

3.1 Lifecycle class

Let's take a look at Lifecycle:

public abstract class Lifecycle {    
//Add observer     
@MainThread    public abstract void addObserver(@NonNull LifecycleObserver observer);   
//Remove observer     
@MainThread    public abstract void removeObserver(@NonNull LifecycleObserver observer);    
//Get current status     
public abstract State getCurrentState();

//Lifecycle event, corresponding to Activity lifecycle method     
public enum Event {        
ON_CREATE,        
ON_START,        
ON_RESUME,        
ON_PAUSE,        
ON_STOP,        
ON_DESTROY,        
ON_ANY  //Can respond to any event     
}       
 
//Lifecycle state  
(Event Is an event that enters this state)    
public enum State {        
        DESTROYED,        
        INITIALIZED,        
        CREATED,       
        STARTED, 
        RESUMED;       

 //Judge at least one state        
 public boolean isAtLeast(@NonNull State state) {
            return compareTo(state) >= 0;        
  }    
}

Lifecycle uses two main enumerations to track the lifecycle state of its associated components:

  1. Event, life cycle events, which correspond to Activity/Fragment life cycle methods.
  2. State, life cycle state, and event refers to the event entering a state. Event trigger timing:
  • ON_CREATE,ON_START,ON_ The resume event is distributed after the method corresponding to the lifecycle owner is executed.
  • ON_PAUSE,ON_STOP,ON_ The destroy event is distributed before the method call corresponding to the lifecycle owner. This ensures that the lifecycle owner is in this state.

There is a clear picture on the official website:

3.2 implementation of lifecycle owner by activity

As mentioned earlier, Activity implements lifecycle owner, so getLifecycle() can be used directly. Specifically, in android.Activity.componentactivity:

//Android x.activity.componentactivity. Some other codes are ignored here. We only look at the public related to Lifecycle   class   ComponentActivity   extends   androidx.core.app.ComponentActivity   implements   LifecycleOwner{     ...       
private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);    
...
@Override    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mSavedStateRegistryController.performRestore(savedInstanceState);
        ReportFragment.injectIfNeededIn(this); //Distributing lifecycle events using ReportFragment         
if (mContentLayoutId != 0) {            
setContentView(mContentLayoutId);
        }
    }    
@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);    
}    
@NonNull    
@Override    
public Lifecycle getLifecycle() {        
      return mLifecycleRegistry;    
  }
}

Some other codes are ignored here. We only look at Lifecycle.

See that the ComponentActivity implements the interface LifecycleOwner and returns the LifecycleRegistry instance in getLifecycle(). As mentioned earlier, LifecycleRegistry is the specific implementation of Lifecycle.

Then, in onSaveInstanceState(), set the state of mlife cycleregistry to State.CREATED, and then why not? Why not handle it in other life cycle methods? What? It's different from what you guessed.   Don't worry, there is a line in onCreate(): reportfragment. Injectifneedin (this);, which is the key.

3.3 life cycle event distribution - ReportFragment

//Fragment s dedicated to distributing lifecycle events
public class ReportFragment extends Fragment {

        public static void injectIfNeededIn(Activity activity) {
        if (Build.VERSION.SDK_INT >= 29) {
            //In API   29 and above, you can register callback directly   Get lifecycle             
             activity.registerActivityLifecycleCallbacks(                   
         new LifecycleCallbacks());       
 }        
//Before API29, fragment was used   Get lifecycle         
    if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
            manager.beginTransaction().add(new ReportFragment(), REPORT_FRAGMENT_TAG).commit();            manager.executePendingTransactions();       
   }   
 }    

@SuppressWarnings("deprecation")    
static void dispatch(@NonNull Activity activity, @NonNull Lifecycle.Event event) {        
    if (activity instanceof LifecycleRegistryOwner) {//It's abandoned here. Don't look             
((LifecycleRegistryOwner) activity).getLifecycle().handleLifecycleEvent(event);
            return; 
       }       

 if (activity instanceof LifecycleOwner) {
            Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();
            if (lifecycle instanceof LifecycleRegistry) {
                ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);//Use the handlellifecycle event method of LifecycleRegistry to process events
            }       
    }    
}    

@Override    
public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        dispatch(Lifecycle.Event.ON_CREATE);    
}
@Override   
 public void onStart() {
        super.onStart();
        dispatch(Lifecycle.Event.ON_START);
    }   
 @Override    
public void onResume() {
        super.onResume();
        dispatch(Lifecycle.Event.ON_RESUME);
    }    
@Override
    public void onPause() {
        super.onPause();
        dispatch(Lifecycle.Event.ON_PAUSE);
    }    
...ellipsis onStop,onDestroy       

 private void dispatch(@NonNull Lifecycle.Event event) {
        if (Build.VERSION.SDK_INT < 29) {            
dispatch(getActivity(), event);       
     }   
 }        

//In API   29 and above, using the lifecycle callback     
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);       
   }       
 ...ellipsis onStop,onDestroy
    }
}

First, the versions of injectifneedin() are distinguished: directly register the lifecycle callback using the registerActivityLifecycleCallbacks of the activity in API 29 and above, and then add a ReportFragment to the current activity. Note that this fragment has no layout.

Then, both the lifecycle methods of LifecycleCallbacks and fragment s finally go to the dispatch (activity, lifecycle. Event) method, which internally uses the handlellifecycle event method of LifecycleRegistry to process events.

The function of ReportFragment is to obtain the life cycle, because the life cycle of fragment depends on the activity. The advantage is to separate this part of logic and realize the non-invasive of activity. If you are familiar with the image loading library Glide, you will know that it also uses transparent fragment to obtain the life cycle.

3.4 lifecycle event handling - lifecycle registry

Here, the processing of lifecycle events has shifted to   LifecycleRegistry   Medium:

//LifecycleRegistry.java   
//The system defined map that saves the Observer can be added or deleted during traversal     
private FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap = new FastSafeIterableMap<>(); 
               
public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {        
    State next = getStateAfter(event);//Gets the state to be in after the event occurs         
    moveToState(next);//Move to this state     
}    

private void moveToState(State next) {
        if (mState == next) {
            return;//If it is consistent with the current status, it will not be processed
        }
        mState = next; //Assign new status
        if (mHandlingEvent || mAddingObserverCounter != 0) {
            mNewEventOccurred = true;
            return;
        }
        mHandlingEvent = true;
        sync(); //Synchronize lifecycle states to all observers
        mHandlingEvent = false;
    }

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.");        
          }
        while (!isSynced()) {  //isSynced() means   All observers are synchronized
            mNewEventOccurred = false;
            //mObserverMap is   After adding observer in activity   The map used to store the observer
            if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
                backwardPass(lifecycleOwner);
            } 
           Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
            if (!mNewEventOccurred && newest != null
                    && mState.compareTo(newest.getValue().mState) > 0) {
                forwardPass(lifecycleOwner);
            }
        }
        mNewEventOccurred = false;
    }
    ...

         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);
    }

The logic is clear: use getStateAfter() to get the state to be in after the event occurs (see the previous figure for a good understanding), moveToState() is to move to a new state, and finally use sync() to synchronize the lifecycle state to all observers.

Note that there is a while loop in sync(), which is obviously traversing the observer. It is obvious that the observer is stored in the mObserverMap, and the addition of the observer by the mObserverMap is obviously the use of getLifecycle().addObserver() in the Activity. Here:

//LifecycleRegistry.java 
   @Override
    public void addObserver(@NonNull LifecycleObserver observer) 
        State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
        //Observer with state, the function of this state: after a new event is triggered   When traversing to notify all observers, judge whether the observer has been notified
        ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
        ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
        //With observer as the key and observer withstate as the value, save it to the mobervermap

        if (previous != null) {
            return;//It has been added and will not be processed
        }
        LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
        if (lifecycleOwner == null) {
            return;//lifecycleOwner exits without processing
        }
 //The logic of the following code: the state of the new observer is changed through the while loop   Continuously   Synchronize to the latest state mState.     
//It means that although it may be added late, the previous events are distributed to you one by one (upEvent method), that is, stickiness
        boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;
        State targetState = calculateTargetState(observer);//Calculate target status
        mAddingObserverCounter++; 
       while ((statefulObserver.mState.compareTo(targetState) < 0
                && mObserverMap.contains(observer))) {
            pushParentState(statefulObserver.mState); 
           statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
            popParentState();
            // mState / subling may have been changed recalculate
            targetState = calculateTargetState(observer);
        }
        if (!isReentrance) {
            sync();
        } 
       mAddingObserverCounter--;
    }

Use observer to create an observer with state. Observer is used as the key and observer with state is used as the value and stored in the mObserverMap. Then make a security judgment. Finally, continuously synchronize the state of the new observer to the latest state mState, which means that although it can be added late, the previous events will be distributed to you one by one, that is, stickiness.

Go back to the while loop of sync() and see how to handle the distribution event:

    private void sync() {
        LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
        if (lifecycleOwner == null) {
            Log.w(LOG_TAG, "LifecycleOwner is garbage collected, you shouldn't try dispatch "                    + "new events from it.");
            return;
        } 
       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) {
                backwardPass(lifecycleOwner);
            }
            Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
            if (!mNewEventOccurred && newest != null 
                   && mState.compareTo(newest.getValue().mState) > 0) {
                forwardPass(lifecycleOwner);
            }
        }
        mNewEventOccurred = false;
    }

        private boolean isSynced() {
        if (mObserverMap.size() == 0) {
            return true;
         }//The state of the oldest and the latest observers is consistent, and both are the current state of the owner, indicating that the synchronization has been completed
        State eldestObserverState = mObserverMap.eldest().getValue().mState;
        State newestObserverState = mObserverMap.newest().getValue().mState;
        return eldestObserverState == newestObserverState && mState == newestObserverState;
    } 

       private void forwardPass(LifecycleOwner lifecycleOwner) {
        Iterator<Entry<LifecycleObserver, ObserverWithState>> ascendingIterator = mObserverMap.iteratorWithAdditions();
        while (ascendingIterator.hasNext() && !mNewEventOccurred) {//Forward traversal, from old to new
            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));//Get events from observer
                popParentState();
            }
        }
    }

    private void backwardPass(LifecycleOwner lifecycleOwner) {
        Iterator<Entry<LifecycleObserver, ObserverWithState>> descendingIterator = mObserverMap.descendingIterator(); 
       while (descendingIterator.hasNext() && !mNewEventOccurred) {//Reverse traversal, from new to old
            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);//Get events from observer
                popParentState();
            }
        }
    }

The cycle condition is! isSynced(). If the state of the oldest and latest observers is consistent and both are the current state of owner, it indicates that synchronization has been completed.

Enter the loop body before synchronization:

  • mState is smaller than the oldest observer state. Backwardpass (lifecycle owner): distribute from new to old, and recycle downEvent() and observer.dispatchEvent() to continuously distribute events;
  • mState is larger than the latest observer state. Go forward pass (lifecycle owner): distribute from old to new, and recycle upEvent() and observer.dispatchEvent() to continuously distribute events.

Then the observer of observer withstate type gets the event, namely observer. DispatchEvent (lifecycle owner, event). Let's see how it enables the annotated method to execute.

3.5 method execution after event callback

Let's keep looking   ObserverWithState:

    static class ObserverWithState {
        State mState;
        GenericLifecycleObserver mLifecycleObserver;
        ObserverWithState(LifecycleObserver observer, State initialState) {
            mLifecycleObserver = Lifecycling.getCallback(observer);
            mState = initialState;
        }

        void dispatchEvent(LifecycleOwner owner, Event event) {
            State newState = getStateAfter(event);
            mState = min(mState, newState);
            mLifecycleObserver.onStateChanged(owner, event);
            mState = newState;
        }
    }

mState is used to judge whether the observer has been notified when traversing all observers after a new event is triggered, that is, to prevent repeated notifications.

Mlicycleobserver is an instance of GenericLifecycleObserver obtained by using lifecycle.getcallback (observer). GenericLifecycleObserver is an interface that inherits from LifecycleObserver:

//Accept life cycle changes and distribute them to real observers public   interface   LifecycleEventObserver   extends   LifecycleObserver   {
    //Life cycle state change
    void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event);}

In other words, LifecycleEventObserver increases the ability of LifecycleObserver to perceive life cycle state changes.

Look at lifecycle. Getcallback (observer):

    @NonNull
      static LifecycleEventObserver lifecycleEventObserver(Object object) { 
       ...Omit code for many types of judgment
        return new ReflectiveGenericLifecycleObserver(object);
    }

There are many codes to judge the type of observer in the method. We focus on ComponentActivity here, so the implementation class of LifecycleEventObserver is ReflectiveGenericLifecycleObserver:

class ReflectiveGenericLifecycleObserver implements LifecycleEventObserver {
    private final Object mWrapped;
    private final CallbackInfo mInfo;

    ReflectiveGenericLifecycleObserver(Object wrapped) { 
       mWrapped = wrapped; 
       mInfo = ClassesInfoCache.sInstance.getInfo(mWrapped.getClass());//It stores the information of event and annotated method
    }

    @Override
    public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Event event) {
        mInfo.invokeCallbacks(source, event, mWrapped);//Execute the method of the observer corresponding to the event
    }
}

Its onStateChanged() method internally uses the invokeCallbacks method of CallbackInfo, which should be the method of executing the observer.

The classeinfo cache uses a Map to store the callback information of all observers. CallbackInfo is the callback information of the current observer.

Let's take a look at the creation of CallbackInfo instance, ClassesInfoCache.sInstance.getInfo(mWrapped.getClass()):

//ClassesInfoCache.java
    private final Map<Class, CallbackInfo> mCallbackMap = new HashMap<>();//Callback information for all observers
    private final Map<Class, Boolean> mHasLifecycleMethods = new HashMap<>();//Does the observer annotate the life cycle approach

        CallbackInfo getInfo(Class<?> klass) { 
       CallbackInfo existing = mCallbackMap.get(klass);//If the current observer callback information already exists   Direct access  
       if (existing != null) {
            return existing;
        }
        existing = createInfo(klass, null);//No, just collect information and create it
        return existing;
    }

        private CallbackInfo createInfo(Class<?> klass, @Nullable Method[] declaredMethods) {
        Class<?> superclass = klass.getSuperclass();
        Map<MethodReference, Lifecycle.Event> handlerToEvent = new HashMap<>();//Life cycle event arrival   Corresponding method
        ...
        Method[] methods = declaredMethods != null ? declaredMethods : getDeclaredMethods(klass);//Reflection method for acquiring observer
        boolean hasLifecycleMethods = false;
        for (Method method : methods) {//traversal method    The annotation onllifecycle event was found
            OnLifecycleEvent annotation = method.getAnnotation(OnLifecycleEvent.class);
            if (annotation == null) { 
               continue; //No annotation onllifecycle event   Just return
            } 
           hasLifecycleMethods = true;//Annotated onllifecycle event
            Class<?>[] params = method.getParameterTypes(); //Get method parameters
            int callType = CALL_TYPE_NO_ARG; 
           if (params.length > 0) { //With parameters  
               callType = CALL_TYPE_PROVIDER;
                if (!params[0].isAssignableFrom(LifecycleOwner.class)) {
                    throw new IllegalArgumentException(//The first parameter must be lifecycle owner  
                           "invalid parameter type. Must be one and instanceof LifecycleOwner"); 
               }
            } 
           Lifecycle.Event event = annotation.value(); 
           
        if (params.length > 1) { 
               callType = CALL_TYPE_PROVIDER_WITH_EVENT; 
               if (!params[1].isAssignableFrom(Lifecycle.Event.class)) { 
                   throw new IllegalArgumentException(//The second parameter must be Event
                            "invalid parameter type. second arg must be an event"); 
               }
                if (event != Lifecycle.Event.ON_ANY) {
                    throw new IllegalArgumentException(//There are two parameters   Annotation value can only be ON_ANY  
                           "Second arg is supported only for ON_ANY value"); 
               } 
           } 
           if (params.length > 2) { //You cannot have more than two parameters
                throw new IllegalArgumentException("cannot have more than 2 params");
            } 
           MethodReference methodReference = new MethodReference(callType, method);
            verifyAndPutHandler(handlerToEvent, methodReference, event, klass);//Verify the method and add it to the map   handlerToEvent   in
        }
        CallbackInfo info = new CallbackInfo(handlerToEvent);//Acquired   All annotation lifecycle methods, handlerToEvent, construct callback information instances
        mCallbackMap.put(klass, info);//Save the callback information of the current observer into the classeinfo cache  
       mHasLifecycleMethods.put(klass, hasLifecycleMethods);//record   Does the observer annotate the life cycle approach
        return info;
    }
  • If the current observer callback information does not exist, the createInfo() method is used to collect the created callback information
  • First reflect the method to obtain the observer, traverse the method, find the method annotated with onllifecycle event, and verify the parameters of the method.
  • The first parameter must be lifecycle owner; The second parameter must be Event; There are two parameters. The annotation value can only be ON_ANY; You cannot have more than two parameters
  • Verify the method and add it to the map. key is the method and value is the Event. map handlerToEvent is all methods that annotate the life cycle.
  • After traversal, use handlerToEvent to construct the callback information CallbackInfo of the current observer, store it in the mCallbackMap of the ClassesInfoCache, and record whether the observer has annotated the life cycle method.

The overall idea is still very clear. Continue to look at the invokeCallbacks method of CallbackInfo:

    static class CallbackInfo {
        final Map<Lifecycle.Event, List<MethodReference>> mEventToHandlers;//Multiple methods corresponding to Event
        final Map<MethodReference, Lifecycle.Event> mHandlerToEvent;//Method to callback

        CallbackInfo(Map<MethodReference, Lifecycle.Event> handlerToEvent) { 
           mHandlerToEvent = handlerToEvent;
            mEventToHandlers = new HashMap<>(); 
           //Here, traverse the mHandlerToEvent to get mEventToHandlers
            for (Map.Entry<MethodReference, Lifecycle.Event> entry : handlerToEvent.entrySet()) { 
               Lifecycle.Event event = entry.getValue();
                List<MethodReference> methodReferences = mEventToHandlers.get(event); 
               if (methodReferences == null) { 
                   methodReferences = new ArrayList<>();
                    mEventToHandlers.put(event, methodReferences); 
               } 
               methodReferences.add(entry.getKey()); 
           }
        } 

       @SuppressWarnings("ConstantConditions") 
       void invokeCallbacks(LifecycleOwner source, Lifecycle.Event event, Object target) { 
           invokeMethodsForEvent(mEventToHandlers.get(event), source, event, target);//Execute the method corresponding to the event
            invokeMethodsForEvent(mEventToHandlers.get(Lifecycle.Event.ON_ANY), source, event,target);//Execute annotation ON_ANY's method
        } 

       private static void invokeMethodsForEvent(List<MethodReference> handlers,
                LifecycleOwner source, Lifecycle.Event event, Object mWrapped) {
            if (handlers != null) { 
               for (int i = handlers.size() - 1; i >= 0; i--) {//Execute multiple methods corresponding to Event
                    handlers.get(i).invokeCallback(source, event, mWrapped);
                } 
           } 
       } 
   }

It is well understood that the method corresponding to the event is executed and the annotation is executed_ Any's method. mEventToHandlers is obtained by traversing the meventtoevent when creating the CallbackInfo, and stores multiple methods corresponding to each event.

Finally, take a look at handlers.get(i).invokeCallback, that is, in MethodReference:

    static class MethodReference { 
       ... 
       void invokeCallback(LifecycleOwner source, Lifecycle.Event event, Object target) {
            try { 
               switch (mCallType) {
                    case CALL_TYPE_NO_ARG:
                        mMethod.invoke(target);//Without parameters
                        break;
                    case CALL_TYPE_PROVIDER:
                        mMethod.invoke(target, source);//One parameter: lifecycle owner  
                       break; 
                   case CALL_TYPE_PROVIDER_WITH_EVENT:
                        mMethod.invoke(target, source, event);//Two parameters: lifecycle owner, Event  
                       break;
                } 
           }
            ...
        }
...
    }

Execute corresponding methods according to different parameter types.

Here, the whole process is complete. After actually looking at such a large circle, the basic idea is consistent with our conjecture.

Here, the article Android Jetpack architecture component (III) takes you to understand the diagram of Lifecycle (principle chapter). The summary is as follows:

4, Summary

This article first introduces the concepts of Jetpack and AAC, which are the general development tool set officially recommended by Android. AAC is the architecture component, which is the introduction of this series of articles. Then it introduces the basic component Lifecycle of AAC, which enables developers to better manage the Activity/Fragment Lifecycle. Finally, the source code and principle of Lifecycle are analyzed in detail.

Jetpack's AAC is not only the necessary knowledge for our subsequent development of Android, but also the basis for completing the MVVM architecture. Lifecycle is the foundation of AAC, so it is necessary to master this article completely.

end of document

Your favorite collection is my greatest encouragement!
Welcome to follow me, share Android dry goods and exchange Android technology.
If you have any opinions on the article or any technical problems, please leave a message in the comment area for discussion!

Tags: Android Back-end

Posted on Tue, 07 Dec 2021 00:06:25 -0500 by chrischen