LifeCycle Foundation (I)

  • The duties of a LifeCycle

    • A life-cycle function that detects activities or fragments

    • Implementation based on observer design pattern

      • Activity/Fragment: Observable (observed)
      • Will LifeCycle be an Observer?
    • Here is:

  • LifeCycle is not used to listen for the LifeCycle of an Activity/Fragment (using listeners)

    • Engineering structure

    • Ideas:

      • Create a listener class and write functions (listener actions)

        package com.derry.lifecycle.user1 import android.util.Log class MyListener { private val TAG = "MyListener" fun start() = Log.d(TAG, "start run ..." ) fun stop() = Log.d(TAG, "stop run ..." )}Copy the code
      • At MainActivity, instantiate the listener, override the lifecycle function, and call the listener method in it

        package com.derry.lifecycle.user1 import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import Com.derry.lifecycle.R // TODO first build listener to listen for the lifecycle class MainActivity: appactivity () {private var myListener: MyListener ? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) myListener = MyListener() } Override fun onStart() {super.onstart () myListener?.start() Override fun onStop() {super.onstop () myListener?.stop()}Copy the code
    • The results

      • When starting the APP:

      • When exiting APP (press the Back button to exit) :

    • Implementation details:

      • The instantiation listener needs to be declared in the onCreate method in MainActivity (where it is being listened on)

        • It’s really just interclass communication, calling methods of class B from class A
      • It is recommended to write listeners as global variables

      • Notice Kotlin’s, right? Use: is used in declarations and calls

  • Version 2 (Mimicking the MVP architecture with the P-layer listening to the lifecycle)

    • Why does the P layer need to listen for lifecycle functions

      • Scene:

        When the p-layer data needs to be fed back to the Activity, it will have a problem feeding back when the Activity dies. So you need to listen at the P layer

    • Engineering structure

    • Ideas:

      • Create myPresby. kt: Write functions in this (perform actions when listening for different life cycles)

        package com.derry.lifecycle.user2 import android.util.Log class MyPresenter { private val TAG = "MyPresenter" fun onResume() = Log.d(TAG, "onResume run ..." ) fun onPause() = Log.d(TAG, "onPause run ..." )}Copy the code
      • Create MainActivity. Kt

        • At MainActivity, instantiate the listener and override the lifecycle function (where listener methods are called)
        package com.derry.lifecycle.user2 import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import Com.derry.lifecycle.R // The P layer of the TODO second version MVP class MainActivity: AppCompatActivity() {private var myPresenter: MyPresenter ? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) myPresenter = MyPresenter() } Override fun onResume() {super.onresume () myPresenter?.onresume () Override fun onPause() {super.onpause () myPresenter?.onpause () // Human error occurs }}Copy the code
    • Running results:

    • Analysis and summary:

      • This looks similar to using a listener for lifecycle function listening, but is actually mimicking a business scenario; To bring out the thing that will LifeCycle
  • 3rd Edition (Basic Edition)

    • Inheritance: LifecycleOwner will be implemented (this excuse will be implemented in AndroidX)

      • Place the cursor on MainActivity, CTRL+H

    • Structure:

    • Create MainActivity(to associate the observer with the observed)

      package com.derry.lifecycle.user3 import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import Com.derry.lifecycle.R // TODO second version MVP P layer class MainActivity: AppCompatActivity() { override fun onCreate(savedInstanceState: {super.oncreate (savedInstanceState) setContentView(r.layout.activity_main) // Generally in BaseActivity associated with registered // observer and Lifecycle. AddObserver (MyObserver())// Get is omitted in kotlin}}Copy the code
    • Create the observer class MyObserver: Implement the observer interface + use annotations to listen for the lifecycle

      package com.derry.lifecycle.user3 import android.util.Log import androidx.lifecycle.Lifecycle import Androidx. Lifecycle. LifecycleObserver import androidx. Lifecycle. OnLifecycleEvent/eyes/observer class MyObserver: LifecycleObserver {private val TAG = "MyObserver" @onlifecycleEvent (Lifecycle.event.ON_RESUME connectListener() = Log.d(TAG,"connectListener run ..." ) @onlifecycleEvent (Lifecycle.event.on_pause) // Disconnect when the screen is not visible, listen for the Lifecycle with annotations Fun disconnectListener() = Log.d(TAG,"disconnectListener run ..." )}Copy the code
    • Run screenshots: View log files

  • Edition 3 (Plus)

    • Disadvantages of the base version:

      • Use annotations to listen for the lifecycle
      • If you can’t get any environment (Activity, Fragment), you can Toast it and add popover
    • Workaround: Let the observer implement the DefaultLifecycleObserver interface

    • Interface inheritance:

      • DefaultLifecycleObserver->FullLifecycleObserver->LifecycleObserver
    • Observer2 (second pair of eyes)MyObserver2

      package com.derry.lifecycle.user3 import android.util.Log import androidx.lifecycle.DefaultLifecycleObserver import Androidx. Lifecycle. LifecycleOwner / / DefaultLifecycleObserver is LifecycleObserver secondary packaging For user to use the class MyObserver2: DefaultLifecycleObserver { private val TAG = "MyObserver2" override fun onCreate(owner: LifecycleOwner) { super.onCreate(owner) Log.d(TAG,"onCreate run ..." } override fun onResume(owner: LifecycleOwner) { super.onResume(owner) Log.d(TAG,"onResume run ..." ) } override fun onPause(owner: LifecycleOwner) { super.onPause(owner) Log.d(TAG,"onPause run ..." )}}Copy the code
      Register with MainActivity: lifecycle. AddObserver (MyObserver2())Copy the code
    • Engineering specifications, typically observed in BaseActivity registration

    • Application Scenarios:

      • LifeCycle will be used to observe the changes in the Activity, Fragment and do the logical processing

      • For example: pop up only when the screen is visible

        • Wechat: When the phone goes off, it receives a message, but only updates the UI when the page is visible
      • Don’t work when LifeCycle is not visible: using LifeCycle at this time could cause a memory leak

  • Version 4: Inner classes implement interfaces to listen (always feels weird)

    • benefits

      • You don’t have to define additional classes
      • No extra override methods
      • Hierarchical structure makes it look clearer
    • MainActivity

      package com.derry.lifecycle.user4 import android.os.Bundle import android.util.Log import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver Import androidx. Lifecycle. OnLifecycleEvent import com. The derry. Lifecycle. R / / TODO a fourth version will inner class listening class MainActivity: AppCompatActivity() { private val TAG = "MainActivity" override fun onCreate(savedInstanceState: {super.oncreate (savedInstanceState) setContentView(r.layout.activity_main) // Normally registered in BaseActivity lifecycle.addObserver(MyObserver()) } inner class MyObserver : LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) fun onResume() { Log.d(TAG, "Lifecycle call onResume");  // logic} @onlifecycleEvent (Lifecycle.event.on_pause) fun onPause() {log.d (TAG, "Lifecycle call onPause"); Override fun onResume() {super.onresume ()}*/Copy the code
  • Version 5: Interface listening method (more used)

    • Use this in projects

    • Engineering structure:

    • IPresenter

      package com.derry.lifecycle.user5 import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver import  androidx.lifecycle.OnLifecycleEvent interface IPresenter : LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) fun onResume() @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) fun onPause() }Copy the code
    • MainActivity

      package com.derry.lifecycle.user5 import android.os.Bundle import android.util.Log import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver Import androidx. Lifecycle. OnLifecycleEvent import com. The derry. Lifecycle. R / / TODO the fifth version of the interface to monitor method, design patterns, the design of the link, You can see the syntax class MainActivity: AppCompatActivity() {private val TAG = "MainActivity" private var myPresenter: IPresenter ? = null override fun onCreate(savedInstanceState: {super.oncreate (savedInstanceState) setContentView(r.layout.activity_main); Lifecycle. AddObserver (myPresenter!!) }}Copy the code
    • MyPresenter

       package com.derry.lifecycle.user5
       ​
       import android.util.Log
       ​
       class MyPresenter : IPresenter {
           private val TAG = "test"
       ​
           override fun onResume() {
               Log.d(TAG, "Lifecycle call onResume")
           }
       ​
           override fun onPause() {
               Log.d(TAG, "Lifecycle call onPause")
           }
       }
      Copy the code
    • MyPresenter2

       package com.derry.lifecycle.user5
       ​
       import android.util.Log
       ​
       class MyPresenter2 : IPresenter {
           private val TAG = "test"
       ​
           override fun onResume() {
               Log.d(TAG, "Lifecycle call onResume")
           }
       ​
           override fun onPause() {
               Log.d(TAG, "Lifecycle call onPause")
           }
       }
      Copy the code
    • MyPresenter3

       package com.derry.lifecycle.user5
       ​
       import android.util.Log
       ​
       class MyPresenter3 : IPresenter {
           private val TAG = "test"
       ​
           override fun onResume() {
               Log.d(TAG, "Lifecycle call onResume")
           }
       ​
           override fun onPause() {
               Log.d(TAG, "Lifecycle call onPause")
           }
       }
      Copy the code

Source code analysis

  • Engineering structure:

  • Demo code: This is a simulation of a map APP where Lifecycle functions are used to analyze the source code

    MainActivity

    package com.derry.lifecycle.source1 import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import Com.derry.lifecycle.R // TODO is observed // source analysis // not written in the Activity to reduce the coupling? // Google is thinking that you can inherit appactivity, You can also inherit XXXXActivity class MainActivity: appactivity () {override fun onCreate(savedInstanceState: {super.onCreate(savedInstanceState) setContentView(r.layout.activity_main) // Observer == MyLocationListener // 1. Mainline flow, Lifecycle. AddObserver (MyLocationListener())} override fun onResume() {lifecycle. super.onResume() // CREATE ---> START ---> RESUME } override fun onStop() { super.onStop() // initial -> create OnCreate /*addObsever() is an initial state that requires onCreate and onDestroyed*/ / lifecycle.addObserver(MyLocationListener()) } }Copy the code

    MyLocationListener

    package com.derry.lifecycle.source1 import android.util.Log import androidx.lifecycle.Lifecycle import Androidx. Lifecycle. LifecycleObserver import androidx. Lifecycle. OnLifecycleEvent / / map location function simulation of the Observer observers eye, The eye sees what it sees in the MainActivity class MyLocationListener: LifecycleObserver {@onlifecycleEvent (Lifecycle.event.on_create) fun create() = log.d ("Derry", "create is starting system location service..." ) @onlifecycleEvent (Lifecycle.event.on_start) fun start() = log.d ("Derry", "start connect to system location service... ) @onlifecycleEvent (Lifecycle.event.on_resume) fun Resume () = log.d ("Derry", "Resume system location interface display..." ) @onlifecycleEvent (Lifecycle.event.on_pause) fun Pause () = log.d ("Derry", "Pause system closes interface..." ) @onlifecycleEvent (Lifecycle.event.on_stop) fun stop() = log. d("Derry", "stop disconnect system location service..." ) @onlifecycleEvent (Lifecycle.event.on_destroy) fun Destroy () = log.d ("Derry", "Destroy Is destroying system Location services..." )}Copy the code
  • Analysis method:

    • Always grasp the mainline flow (where the decision is to go)
  • Example analysis: how is MyLocationListener called in the system

    • Step: Click the red arrow to view the source code (CTRL+ left mouse button)

      • Jump to MainActivity (Add eyes: Associate observer with observed)

      • Click this interface button to jump to

      • You can see the eye as the construction parameter of the ObserverWithState class. Jump again (to see the specific constructor for ObserverWithState) and click the red arrow

      • In ObserverWithState constructor of a class, the observer can see the eyes, as a function argument passed in the Lifecycling. LifecycleEventObserver (), click continue to jump

      • In Lifecycling. LifecycleEventObserver (), you can see it will be involved in parameter is an object

      • Sliding the mouse wheel, in this last line LifecycleEventObserver, found the object as a parameter, the ReflectiveGenericLifecycleObserver class instantiation, click continue to jump

      • In the image below, you can see the structure of the ReflectiveGenericLifecycleObserver method, to do the staging of the incoming parameters, first in the mWrapped, then use the parameter of the bytecode file (reflective), continue to click on the red arrow

      • Private CallbackInfo createInfo(Class
        klass, @nullable Method[] declaredMethods) {}
      • In the red box below, you can see that the MyLocationListener we are going to create gets its bytecode file by reflection and puts it into the Map: facilitating subsequent hosts (Activity or Fragment life cycle) to be activated by reflection

  • Source code Analysis Lessons: Using Map to improve performance (time for space)

    CallbackInfo getInfo(Class<? < span style = "max-width: 100%; clear: both; min-height: 1em; The next time you encounter this (the same observer), you can fetch it directly from the Map. Most system sources do this to create a Map cache: Existing = McAllbackmap.get (klass); // Existing = McAllbackmap.get (klass); if (existing ! = null) { return existing; } existing = createInfo(klass, null); return existing; }Copy the code
  • Observers will be put into the Map inside, ReflectiveGenericLifecycleObserver – > ClassesInfoCache inside the class

    // Use the cache to store the observer's class annotations and other information in the Map. CallbackInfo info = new CallbackInfo(handlerToEvent); mCallbackMap.put(klass, info); mHasLifecycleMethods.put(klass, hasLifecycleMethods);Copy the code
  • States and events (this is the hard part)

    • When the host LifeCycle occurs, how can it be sensed within that LifeCycle? (Introduce state machine)

    • Let’s solve the problem of how to relate

      • Enter the parent class of MainActivity: AppCompatActivity

      • Enter the parent class of AppCompatActivity: FragmentActivity

      • Enter the FragmentActivity parent: ComponentActivity

      • In this ComponentActivity, you’ve implemented an interface, click on it

      • Discovery: There is this getLifecycle(); This is equivalent to the association in MainActivity lifecycle. AddObserver (MyLocationListener())

  • Start dealing with perception: Go back to the previous step (ComponentActivity class) and look for his onCreate method, which creates a blank (uI-free) Fragment

    • In Gradle source code, it is common to paste a blank Fragment to the place you want to listen on. The host executes onStart, and the blank ReportFragment also executes onStart.

    • Scroll down in ReportFragment. Java, there are six lifecycle functions that are involved in event distribution (version control is done here, and event distribution starts immediately after 29; Above 29, it cuts out, but it still comes back, above;)

    • That’s the interface

  • Now comes the hard part: dealing with event distribution

    • Get the event and throw it inside getStateAfter: get the state next based on the Event and align it based on the state

    • Switch-case: Returns different status for different events

    • Event value codes are displayed

    • Display status value code

  • Event-driven state: This is the state machine

    • ON_RESUME has no backward state
    • MState: records all status
    • MActive: bool. If the state is STAERED or RESUMED, this variable is true. All other states are false
    • State machine diagrams (events to determine the state transition process) : Enumerate values from left to right in ascending order

  • State alignment: Make sure the observer is in the same state as the observed (the observed tends to move faster, e.g. the observed is STARTED, the observer is CREATED)

    • When state alignment is complete (how is this aligned? Where is the code
    • When the states are different, determine whether to go forward (forwardPass) or backward (bankwdPass) by enumerating the type versus size

  • Example: Taking a backward process as an example:

    • If you look at the source code, it does execute the ON_STOP event (in this case, exit by status event)
    ! [image-20211128130400559](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ca60acfdaac54143b25b4384bffd4962~tplv-k3u1fb pfcp-zoom-1.image)Copy the code
    • Example: Advance when the observer is CREATED, the observer is STARTED, and the observer is large

      The observer moves forward and updates the status (observer is smaller than observed when comparing enumeration values)

      • At this point, we need to update the observer, we need to go forward, we need to go into the upEvent function (we get the return value of the function based on the state of the observer (an event that needs to be executed)) and there’s another check,

      • Handles event dispatches, and returns ON_RESUME as the dispatch argument when the observed is STARTED

      • A secondary test is performed here:

      • Continue to click

      • Continue to click

      • Continue (this is the hole left in the front)

      • Go ahead, reflection executes

      • Go ahead, reflection executes

      • That’s it, the ON_RESUME method of MyLocationListener is called by reflection: event distribution is implemented

      • The ON_RESUME corresponding to the annotation handler in MyLocationListener is executed

  • Processing pit: mActive

    • LiveData will have LifeCycle status so it will have many features

      • Unbind resolves memory leaks. When the Activity is DESTROYED, unbind the LiveData observer so that it does not leak memory

      • This LiveData will have the state Lifecycle and can be lazy

    • Fill the hole: register in different positions: onResume, onStop registration

      class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState) setContentView(r.layout.activity_main) // Observer == MyLocationListener // 1. Mainline flow, Lifecycle. AddObserver (MyLocationListener())} override fun onResume() {lifecycle. Super.onresume () // CREATE --> START --> RESUME: Lifecycle. AddObserver (MyLocationListener())} Override fun onStop() {super.onstop () // initial -> create OnCreate /*addObsever() is an initial state that requires onCreate and onDestroyed*/ / lifecycle.addObserver(MyLocationListener()) } }Copy the code
    • State machine correlation:

      • Why do you have a state machine where you just assign values when you update

        • A state machine can only change state based on events
        • This is intended for use by future frameworks, not programmers
      • INITIALIZED is the starting point of the state machine, and the state can only be updated through events
      • Both the observer and the observed can only remain in one state, through which to decide whether to go forward or backward
  • Knowledge of the details

    • Observable –> Host: Implements LifeCycleOwner and uses this interface for maintenance

      • Activity
      • Fragment
    • If you’re using Support4 and not AndroidX, you don’t have Jetpack, you don’t have this interface (AndroidX is the default)

    • Observer: Implements the LifeCycleObserver interface, which is the eye

    • Use LifeCycle. AddObserver (Observer) : And that’s the connection

  • Knowledge supplement:

    • The execution timing of a lifecycle function

    • As shortcut key to view inheritance relationship:

      • Hover the cursor over the class you want to view
      • CTRL+H
    • As shortcut to view the structure of the class

      • ALT+ 7
      • CTRL+F12
    • As shortcut key analysis source code

      • Rewind to the previous step: CTRL+ALT+ left arrow key
      • Advance to the next step: CTRL+ALT+ right arrow key (based on viewing history)
    • How to make giFs:

    • How to implement enumeration size comparison:

    • Factory design pattern

    • reflection

  • Exception handling

    • When importing someone else’s file

      • Exception information

         Caused by: org.gradle.api.internal.plugins.PluginApplicationException: Faile
        Copy the code
      • The solution

        Add the following statement to the file and refresh it

          android.overridePathCheck=true
        Copy the code
    • In one project, I found that it was not running the one I wanted

      • Set the AndroidManifest. XML

      • Start the user1/MainActivity

    • Boot failure

      • Synchronize Gradle files and restart
      • Or process against the log