How to know if your Android App is in background

The Android framework does not provide an easy way to detect if an App has gone into background.

While it’s really easy to know if an activity is visible or not with it’s onStart() / onStop() methods, this does not really tell us much about our application state.

Think this, you may want to be notified as soon as your app has gone into background in order to execute some code.
So what to do? Simple, add your code inside your MainActivity’s onStop() method.


@Override
public void onStop() {

  execBackgroundCode();

  super.onStop();

}

This works well for an App with a single activity, but with more activities you’ll run into troubles as soon as you switch from your MainActivity to the next activity.
Two problems arises:

  1. You have to duplicate your execBackgroundCode() call inside the other activity’s onStop() method
  2. Even with that it won’t work 🙂

Why? Simple, your MainActivity’s onStop() will be invoked by the system before starting the next activity and your execBackgroundCode() method will be executed resulting in your App executing the background code even if it’s not in background.

This was the case with my last App Secrets.
I needed to know as soon as possible if my app was in background in order to start a session timeout for the logged user.
I came up with a simple solution. Using an Handler and a postDelayed() call.
Let’s see how it works.

If you don’t know what a Handler is please have a look at the android dev docs. To tell it the simple way, it is basically a software component that can handle messages and execute some code when a message is received, both immediately or scheduled at some point in the future. The useful part here is that scheduled messages can be un-scheduled if needed.

I used this idea to solve my problem. By using a custom BaseActivity class as the parent class for all of my activities, I can schedule my execBackgroundCode() call inside the BaseActivity‘s onStop() method to be executed, let’s say, 3 seconds after the onStop() returns.
In my BaseActivity‘s onStart() I just have to un-schedule the message, so any transition between activities does not trigger the call to execBackgroundCode().
On the other hand, if any of my activities goes to the background the call will be executed.

The only disadvantage of this technique is the mandatory 3 seconds timeout before knowing if the app is in background, it is three seconds because this value is a good compromise between the activities switch time (up to 2 seconds with complex activities on slower devices) and the time we have to wait in order to know whether or not our app is in background. A small value of, let’s say, 500 ms here would trigger our execBackgroundCode() call almost every time we start another activity. A bigger value is not a good choice either because it mandates a longer wait.

Step 1: Create a base activity

We’ll need a base activity, which has to be the common ancestor between all of our activities. This is required because we have to implement some logic inside onStart() and onStop() and we need that logic for all of our activities.


public class BaseActivity extends Activity {
}

We also have to edit every activity in our app to make it extend the new BaseActivity.

Step 2: Create a Handler instance

Now we have to create our static Handler instance, it is static because every activity must be able to access the same Handler object, activity A starts activity B, so it schedules the message on mHandler, activity B starts and un-schedules the message from the same mHandler.


public class BaseActivity extends Activity {

    private static Handler mHandler = new Handler();

}

Step 3: Post a callback inside onStop()

Here comes the interesting part, we have to post a callback on the mHandler object to be executed some seconds after the onStop() has been called.
Our callback is nothing more than a Runnable object with our execBackgroundCode() method call inside it’s run() method.


public class BaseActivity extends Activity {

    private static Handler mHandler = new Handler();

    @Override
    public void onStop() {
       super.onStop();

       mHandler.postDelayed(new Runnable() {
      
           @Override
           public void run() {

               execBackgroundCode();

           }

       }, 3000); // The Runnable is scheduled to run at t+3s (passed value is in ms)
    }

}

Step 4: Cancel the callback inside onStart()

Last thing to do is to cancel, or un-schedule, our Runnable inside the BaseActivity‘s onStart() method.


public class BaseActivity extends Activity {

    private static Handler mHandler = new Handler();

    @Override
    public void onStart() {
       super.onStart();

       // This will remove ANY message or callback 
       // currently scheduled or queued
       mHandler.removeCallbacksAndMessages(null);

    }

    @Override
    public void onStop() {
       super.onStop();

       mHandler.postDelayed(new Runnable() {
      
           @Override
           public void run() {

               execBackgroundCode();

           }

       }, 3000); // The Runnable is scheduled to run at t+3s (passed value is in ms)
    }

}

Conclusion

And this is it. Hope it will be useful as it was for me.
This is, up to now, the best and the cleanest approach I found to handle this situation. Other approaches have been developed, things like overriding the startActivity() method and all of it’s variants and keeping flags here and there, but I never loved flags, it’s too easy to mess around with flags.

Comments are free 🙂

Enjoy 😉

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s