Tom McFarlin Tom McFarlin - 1 year ago 115
Android Question

Detect when app is opened/resumed

I'd like to check-in and checkout a user with the server every time that the app is opened/closed, whether it is launched or resumed from the task drawer. Is there is a way to do this while avoiding having to call a function in each Activity?

Thank you!

Answer Source

The answer provided by d60402 here and the suggestion by Hanno Binder to register activity callbacks using Application.registerActivityLifecycleCallbacks() led me to this solution.

I extended Application and registered callbacks to Activity methods onPause and onStart as shown below. In these methods a timer is started/stopped (one activity being exited where onPause is called, a new one being entered where onStart is called). The flag "wasInBackground" is toggled when the app determined to be in the background/foreground (true/false). If the app was in the background when the onStart callback is run, "appEntered" is called. If the time passed between onPause and onStart callbacks is greater than a specified time (giving enough time for activity transitions) "appExited" is called where the app session is considered to be finished.

public class MyApplication extends Application {

public static final String LOG_TAG = "MyApp";

public boolean wasInBackground = true;

private AppSession appSession;
private Timer mActivityTransitionTimer;
private TimerTask mActivityTransitionTimerTask;
private final long MAX_ACTIVITY_TRANSITION_TIME_MS = 2000;  // Time allowed for transitions

Application.ActivityLifecycleCallbacks activityCallbacks = new Application.ActivityLifecycleCallbacks() {

    @Override
    public void onActivityResumed(Activity activity) {

        if (wasInBackground) {
            //Do app-wide came-here-from-background code
            appEntered();
        }
        stopActivityTransitionTimer();
    }

    @Override
    public void onActivityPaused(Activity activity) {
        startActivityTransitionTimer();
    }

    ...

};

@Override
public void onCreate() {
    super.onCreate();
    registerActivityLifecycleCallbacks(activityCallbacks);
}

public void startActivityTransitionTimer() {
    this.mActivityTransitionTimer = new Timer();
    this.mActivityTransitionTimerTask = new TimerTask() {
        public void run() {
            // Task is run when app is exited
            wasInBackground = true;
            appExited();
        }
    };

    this.mActivityTransitionTimer.schedule(mActivityTransitionTimerTask,
            MAX_ACTIVITY_TRANSITION_TIME_MS);
}

public void stopActivityTransitionTimer() {
    if (this.mActivityTransitionTimerTask != null) {
        this.mActivityTransitionTimerTask.cancel();
    }

    if (this.mActivityTransitionTimer != null) {
        this.mActivityTransitionTimer.cancel();
    }

    this.wasInBackground = false;
}

private void appEntered() {
    Log.i(LOG_TAG, "APP ENTERED");

    appSession = new AppSession();
}

private void appExited() {
    Log.i(LOG_TAG, "APP EXITED");

    appSession.finishAppSession();

    // Submit AppSession to server
    submitAppSession(appSession);
    long sessionLength = (appSession.getT_close() - appSession.getT_open())/1000L;
    Log.i(LOG_TAG, "Session Length: " + sessionLength);
}