LifeCycle of Jetpack (1) Use

LifeCycle , from the bottom of the Jetpack ecological chain.

The role of LifeCycle is to perceive the life cycle of the component (Activity/Fragment), and execute the tasks we assign to LifeCycle in the appropriate life cycle . LifeCycle insists on implementing Jetpack's Slogan, Less Code, and less bugs! Use it, you will have no crashes offline, no bugs online, and get off work on time every day.

It seems a bit off topic, so pull it back.

Although it is said to come from the bottom of the Jetpack ecological chain, it is actually the most indispensable component in the Jetpack family. Look at LiveData on the left, and ViewModel on the right, they show a disdainful expression, "In the days without you, everyone is not the same!"

It seems to make a little sense, LifeCycle first appeared in version 26.1.0 of the Support library era . Before that, how did you perceive the statement cycle? At this moment, a programmer with still thick hair flung out his ancestral code from the darkness.

public class LocationUtil {

    public void startLocation() {
        ......
    }

    public void stopLocation() {
        ......
    }

}

Then, you have to use it like this.

public class LocationActivity extends AppCompatActivity {

    private LocationUtil locationUtil = new LocationUtil();

    @Override
   public void  onResume(){
       locationUtil.startLocation();
       ......
   }

   @Override
   public void onPause(){
       locationUtil.stopLocation();
       .....
   }
}

The programmer boasted, "My LocationUtil has been tested for a long time, perfectly solves the life cycle problem, and will never leak memory!"

That's right, it's fine for you to use alone. But for a modern large-scale project, if there are twenty pages that need to use your LocationUtil, these twenty pages are assigned to five programmers to complete. Can you ensure that all lifecycle code is added as you expect? Or you have already left the job and have not left detailed documents, but you will have to be greeted by a new employee because of an inexplicable memory leak someday.

In another extreme situation, the damn product manager (throwing the pot) asked you onCreate()to onDestroyenable and disable positioning in and respectively, instead of the original onResume()and onPause(). At this moment, do you have the feeling that you want to take out a forty-meter sword?

Your way of writing, a bunch of codes, is so fragile!

He blushed, and could only defend weakly, "You go ahead, show me your code!"

I have been prepared to speak with code. First let LocationUtil implement the LifeCycleObserver interface.

class LocationUtil( ) : LifeCycleObserver {
  @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
  fun startLocation( ){
    ......
  }

  @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
  fun stopLocation( ){
    ......
  }
}

Then for any lifecycle component that implements the LifecycleOwner interface, if you need to use LocationUtil, you only need to add the following line of code.

lifecycle.addObserver(LocationUtil( ))

I let the third-party components such as LocationUtil get the life cycle inside themselves, so that the life cycle logic processing that originally needs to be carried out in the life cycle component Activity/Fragment can be directly completed inside the component, further decoupling. Even in the face of the abnormal product manager's requirements mentioned above, you only need to modify the internal implementation of LocationUtil, without any external modifications. See, many times I feel that other people's needs are very unreasonable, but in fact it is my own problem.

There was no sound all around, and I should have been stunned by it. This is just my most basic usage, and I will come to some advanced ones below, pay attention, don't blink.

Monitor application front and back switching

Some banking apps have this function. When the app is switched to the background, it will give the user a prompt, "xx mobile banking is running in the background, please pay attention to safety!". It is very simple to implement with my LifeCycle.

class KtxAppLifeObserver : LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onForeground() {
        Ktx.app.toast("应用进入前台")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun onBackground() {
        Ktx.app.toast("应用进入后台")
    }
}

Then when the application starts, such as ContentProvier, Application, call the following code:

 ProcessLifecycleOwner.get().lifecycle.addObserver(KtxAppLifeObserver())

Through the code you also found that it was realized ProcessLifecycleOwnerthrough . It can perceive the life cycle of the entire application process, so that it is easy to monitor the switching between the front and back of the application.

Global Management Activity

I believe that you have all done such a function. Under certain circumstances, you must finish all the opened activities, or close the specified activity. The usual practice is to save the opened or closed Activity in the life cycle callback of BaseActivity. Although the implementation is quite elegant, how to reduce the burden on the increasingly bloated BaseActivity? It's time for me to play LifeCycle again.

class KtxLifeCycleCallBack : Application.ActivityLifecycleCallbacks {

    override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
        KtxManager.pushActivity(activity)
        "onActivityCreated : ${activity.localClassName}".loge()
    }

    override fun onActivityStarted(activity: Activity) {
        "onActivityStarted : ${activity.localClassName}".loge()
    }

    override fun onActivityResumed(activity: Activity) {
        "onActivityResumed : ${activity.localClassName}".loge()
    }

    override fun onActivityPaused(activity: Activity) {
        "onActivityPaused : ${activity.localClassName}".loge()
    }

    override fun onActivityDestroyed(activity: Activity) {
        "onActivityDestroyed : ${activity.localClassName}".loge()shejiyuanze
        KtxManager.popActivity(activity)
    }

    override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle?) {
    }

    override fun onActivityStopped(activity: Activity) {
        "onActivityStopped : ${activity.localClassName}".loge()
    }
}

Through another member of my family, Application.ActivityLifecycleCallbacksyou can monitor all life cycles of all activities. Just register this Callback in Application.

application.registerActivityLifecycleCallbacks(KtxLifeCycleCallBack())

According to the principle of single responsibility , a class does one thing. This way of writing concentrates the management responsibilities of the Activity into one class, reducing code coupling. There are two problems with the original way of writing. First, you must inherit BaseActivity to have the function of managing the current Activity. This again involves collaborative development, not wanting to inherit, or forgetting to inherit. Second, letting BaseActivity assume too many responsibilities does not conform to the basic design principles.

Handler that automatically handles the life cycle

From the idea of ​​programs are not apes. Remove the Handler message in the onDestroy method without additional manual processing to avoid memory leaks.

public class LifecycleHandler extends Handler implements LifecycleObserver {

    private LifecycleOwner lifecycleOwner;

    public LifecycleHandler(final LifecycleOwner lifecycleOwner) {
        this.lifecycleOwner = lifecycleOwner;
        addObserver();
    }

    public LifecycleHandler(final Callback callback, final LifecycleOwner lifecycleOwner) {
        super(callback);
        this.lifecycleOwner = lifecycleOwner;
        addObserver();
    }

    public LifecycleHandler(final Looper looper, final LifecycleOwner lifecycleOwner) {
        super(looper);
        this.lifecycleOwner = lifecycleOwner;
        addObserver();
    }

    public LifecycleHandler(final Looper looper, final Callback callback, final LifecycleOwner lifecycleOwner) {
        super(looper, callback);
        this.lifecycleOwner = lifecycleOwner;
        addObserver();
    }

    private void addObserver() {
        notNull(lifecycleOwner);
        lifecycleOwner.getLifecycle().addObserver(this);
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    private void onDestroy() {
        removeCallbacksAndMessages(null);
        lifecycleOwner.getLifecycle().removeObserver(this);
    }
}

A Smarter Event Bus

Speaking of the development history of the event bus framework, I recommend an article by the Meituan technical team on the evolution of the Android message bus: replacing RxBus and EventBus with LiveDataBus . Whether it is EventBus or RxBus, in fact, they do not have the ability to perceive the life cycle. It is reflected in the code that the anti-registration method needs to be displayed and called. LiveDataBus is implemented based on LiveData, and LiveData obtains the life cycle awareness ability through LifeCycle, no manual anti-registration is required, and there is no risk of memory leaks.

LiveEventBus
	.get("key_name", String.class)
	.observe(this, new Observer<String>() {
	    @Override
	    public void onChanged(@Nullable String s) {
	    }
	});

Subscribe anytime, unsubscribe automatically, it's that simple.

Use with coroutines

Coroutine is an upstart in Android's asynchronous processing solution, not only my LifeCycle, ViewModel, LIveData and other Jetpack components provide specific support for it.

Add androidx.lifecycle:lifecycle-runtime-ktx:2.2.0-alpha01or . The support library defines for each LifeCycleobject LifecycleScope. Coroutines started within this scope are automatically canceled when the LifeCycle is destroyed. You lifecycle.coroutineScopecan lifecycleOwner.lifecycleScopeaccess Lifecycle through the or property CoroutineScope. Here is a simple example:

class MyFragment: Fragment() {
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            viewLifecycleOwner.lifecycleScope.launch {
                val params = TextViewCompat.getTextMetricsParams(textView)
                val precomputedText = withContext(Dispatchers.Default) {
                    PrecomputedTextCompat.create(longTextContent, params)
                }
                TextViewCompat.setPrecomputedText(textView, precomputedText)
            }
        }
    }

For more usage, please refer to the introduction on the official website Using Kotlin Coroutines with Architecture Components .

principle

"Finally understand" series: Complete analysis of Jetpack AAC (-) Lifecycle fully mastered!

Guess you like

Origin blog.csdn.net/m0_49508485/article/details/127080829