Lifecycle of Android Jetpack Series

Lifecycle of Android Jetpack Series solution


foreword
Lifecycle of Android Jetpack Series.Lifecycle is a component used in Jetpack architecture components to perceive the life cycle. Using Lifecycles can help us write more concise and maintainable code related to the life cycle.
life cycle

Lifecycle of Android Jetpack Series.I believe everyone is familiar with this simple and important knowledge of the life cycle. Suppose we now have such a simple requirement:
This requirement is just an example, and of course there is no such requirement in real development:
When the Activity is visible, we do a counting function, increase the count by 1 every second, stop the count when the Activity is invisible, and set the count to 0 when the Activity is destroyed
OK, So easy~, create a new Main3Activity and write the code as follows:
public class Main3Activity extends AppCompatActivity {
private static final String TAG = "Main3Activity";
int count = 0;
/**
* 是否计数
*/
private boolean whetherToCount = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
}
@Override
protected void onResume() {
super.onResume();
whetherToCount = true;
new Thread(new Runnable() {
@Override
public void run() {
while (whetherToCount) {
try {
Thread.sleep(1000);
count++;
Log.d(TAG, "onResume: " + count);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
@Override
protected void onStop() {
super.onStop ();
Log.d (TAG, " onStop : ----");
whetherToCount = false;
}
@Override
protected void onDestroy ( ) {
super.onDestroy ();
whetherToCount = false;
count = 0;
}
}

The result of running is as follows:
In line with our expectations, you may look at me with contempt, so bloated, I am a person who has learned object-oriented, so you put the work in a class called WorkUtil
public class WorkUtil {
private static final String TAG = " WorkUtil ";
private boolean whetherToCount = true;
private int count = 0;
public void start( ) {
new Thread( new Runnable() {
@Override
public void run( ) {
while (whetherToCount) {
try {
Thread.sleep(1000);
count++;
Log.d(TAG, "start: " + count);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
public void onStop ( ) {
whetherToCount = false;
}
public void onDestory ( ) {
count = 0;
}
}

Then execute the corresponding methods in the life cycle of the activity, which feels great~
However, this is still not enough decoupling. If there are too many methods, the code in the view will become more and more bloated. Is there a better solution? This is what we call Lifecycle today. We will come back and optimize the above code later.

Lifecycle of Android Jetpack Series .Manage Lifecycles with Lifecycle


explain how to use Lifecycle by rewriting the WorkUtil class, and let the WorkUtil class implement LifecycleObserver
We use the OnLifecycleEvent annotation to annotate the life cycle performed by the method, as follows:
public class WorkUtil implements LifecycleObserver {
private static final String TAG = " WorkUtil ";
private boolean whetherToCount = true;
private int count = 0;
@OnLifecycleEvent ( Lifecycle.Event.ON_RESUME ) _
public void start() {
new Thread(new Runnable() {
@Override
public void run() {
while (whetherToCount) {
try {
Thread.sleep(1000);
count++;
Log.d(TAG, "start: " + count);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onStop() {
whetherToCount = false;
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
public void onDestory() {
count = 0;
}
}

Just register in Activity:
getLifecycle ( ) .addObserver (new WorkUtil ());

Isn't this much more concise, so why can we use getLifecycle (). addObserver (new WorkUtil ()); directly in Activity? In fact , LifecycleOwner.getLifecycle is used. LifecycleOwner is a single-method interface, indicating that the class has Lifecycle , And if the activity inherits from AppcompatActivity or Fragment inherits from androidx.fragment.app.Fragment they themselves are an instance of LifecycleOwner , which is done automatically by the AndroidX library for us .

Lifecycle of Android Jetpack Series.Custom LifecycleOwner


What if our Activity inherits not AppcompatActivity but Activity for various reasons?

We can see that at this time, we can't use getLifecycle directly , but to customize a LifecycleOwner , we let Activity inherit from LifecycleOwner ,
Use the LifecycleRegistry defined as follows:
@Override
protected void onCreate ( Bundle savedInstanceState ) {
super.onCreate ( savedInstanceState );
setContentView(R.layout.activity_main3);
lifecycleRegistry = new LifecycleRegistry(this);
getLifecycle().addObserver(new WorkUtil());
}

@NonNull
@Override
public Lifecycle getLifecycle() {
return lifecycleRegistry;
}

Lifecycle of Android Jetpack Series.In this way, we have implemented a custom LifecycleOwner , but most of the time we still don't need to customize it.
Elegantly detect the status of the application front and back
In many businesses, we need to monitor the status of the front and back of the application, such as starting the cache task in the foreground and stopping the cache task in the background. In fact, there are many methods, such as
Use the method we mentioned above to monitor BaseActivity , but it is not elegant enough. If we want to monitor the life cycle of all Activty , we need to use ActivityLifecycleCallbacks . We create a new ForegroundCallbacks class to implement ActivityLifecycleCallbacks
public class ForegroundCallbacks implements Application.ActivityLifecycleCallbacks {
private static final String TAG = "ForegroundCallbacks";
@Override
public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
Log.d(TAG, "onActivityCreated: " + activity.getComponentName());
}
@Override
public void onActivityStarted(@NonNull Activity activity) {
Log.d(TAG, "onActivityStarted: "+ activity.getComponentName());
}
@Override
public void onActivityResumed(@NonNull Activity activity) {
Log.d(TAG, "onActivityResumed: "+ activity.getComponentName());
}
@Override
public void onActivityPaused(@NonNull Activity activity) {
Log.d(TAG, "onActivityPaused: "+ activity.getComponentName());
}
@Override
public void onActivityStopped(@NonNull Activity activity) {
Log.d(TAG, "onActivityStopped: "+ activity.getComponentName());
}
@Override
public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {
Log.d(TAG, "onActivitySaveInstanceState: "+ activity.getComponentName());
}
@Override
public void onActivityDestroyed(@NonNull Activity activity) {
Log.d (TAG, " onActivityDestroyed : "+ activity.getComponentName ());
}
}

Add an initialization method:
/**
* Initialize foregroundCallbacks
*
* @param appApplication application
*/
public static ForegroundCallbacks init ( AppApplication appApplication ) {
instance = new ForegroundCallbacks ( );
appApplication.registerActivityLifecycleCallbacks (instance);
return instance;
}

Register in Application:
ForegroundCallbacks.init (this);

The running project log is as follows:

Now we know that we must judge in the two methods of onActivityResumed and onActivityPaused , but it is definitely not to say that entering resumed is in the foreground, entering paused is the background, because our application will have multiple activities, only the first activity is in the foreground When we are prompted to be in the foreground, we are prompted to be in the background only when all activities are not visible. According to this idea, we write the corresponding processing.
First define a method in the interface that calls back in the foreground or in the background

public interface Listener {
/**
* reception
*/
public void onBecameForeground ( );
/**
* In the background
*/
public void onBecameBackground ( );
}

define marker bits
private Runnable runnable ;
/**
* Whether onResumed has been executed
*/
private boolean onResumed = false;
/**
* 是否执行过onPaused
*/
private boolean onPaused = true;

@Override
public void onActivityResumed(@NonNull Activity activity) {
Log.d(TAG, "onActivityResumed: " + activity.getComponentName());
onPaused = false;
if (runnable != null){
handler.removeCallbacks(runnable);
}
handler.postDelayed(runnable = new Runnable() {
@Override
public void run() {
if (!onResumed) {
listener.onBecameForeground();
onResumed = true;
}
}
},600);
}
@Override
public void onActivityPaused(@NonNull Activity activity) {
Log.d(TAG, "onActivityPaused: " + activity.getComponentName());
onPaused = true;
if (runnable != null){
handler.removeCallbacks(runnable);
}

handler.postDelayed(runnable = new Runnable() {
@Override
public void run() {
if (onResumed && onPaused) {
onResumed = false;
listener.onBecameBackground ();
}
}
}, 600);
}

The reason why we delay 0.6s here is to avoid starting a new activity and mistakenly thinking it is in the background when the old activity page is not visible. However, in real business scenarios, it is still necessary to optimize according to the details and add event callbacks in applicaton
ForegroundCallbacks.init (this ) .addListener (new ForegroundCallbacks.Listener () {
@Override
public void onBecameForeground ( ) {
Log.d (TAG, " onBecameForeground : in the foreground");
}
@Override
public void onBecameBackground ( ) {
Log.d (TAG, " onBecameBackground : in the background");
}
});

Related Articles

Explore More Special Offers

  1. Short Message Service(SMS) & Mail Service

    50,000 email package starts as low as USD 1.99, 120 short messages start at only USD 1.00