How to detect user inactivity in Android

2019-01-01 08:04发布

User start my app and logs in.
Selects Session Timeout to be 5 mins.
Does some operations on the app. (all in foreground)
Now User bring Myapp to background and starts some other app.
----> Count down timer starts and logs out user after 5 mins
OR user turns the screen OFF.
----> Count down timer starts and logs out user after 5 mins

I want the same behavior even when the app is in the foreground but user doesn't interact with the app for a long-time say 6-7 mins. Assume the screen is ON all the time. I want to detect kind of user inactivity (No interaction with app even though the app is in the foreground) and kick start my count down timer.

13条回答
几人难应
2楼-- · 2019-01-01 08:53

I don't know a way of tracking inactivity but there is a way to track user activity. You can catch a callback called onUserInteraction() in your activities that is called every time the user does any interaction with the application. I'd suggest doing something like this:

@Override
public void onUserInteraction(){
    MyTimerClass.getInstance().resetTimer();
}

If your app contains several activities, why not put this method in an abstract super class (extending Activity) and then have all you activities extending it.

查看更多
有味是清欢
3楼-- · 2019-01-01 08:53

I think it needs to be by combining the timer with the last activty time.

So like this:

  1. In onCreate(Bundle savedInstanceState) start a timer, say 5 minutes

  2. In onUserInteraction() just store the current time

Pretty simple so far.

Now when the timer pop do like this:

  1. Take the current time and subtract the stored interaction time to get timeDelta
  2. If timeDelta is >= the 5 minutes, you are done
  3. If timeDelta is < the 5 minutes start the timer again, but this time use 5 minutes - the stored time. In other words, 5 minute form the last interaction
查看更多
像晚风撩人
4楼-- · 2019-01-01 08:54

I came up with a solution that I find quite simple based on Fredrik Wallenius's answer. This a base activity class that needs to be extended by all activities.

public class MyBaseActivity extends Activity {

    public static final long DISCONNECT_TIMEOUT = 300000; // 5 min = 5 * 60 * 1000 ms


    private Handler disconnectHandler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            // todo
            return true;
        }
    });

    private Runnable disconnectCallback = new Runnable() {
        @Override
        public void run() {
            // Perform any required operation on disconnect
        }
    };

    public void resetDisconnectTimer(){
        disconnectHandler.removeCallbacks(disconnectCallback);
        disconnectHandler.postDelayed(disconnectCallback, DISCONNECT_TIMEOUT);
    }

    public void stopDisconnectTimer(){
        disconnectHandler.removeCallbacks(disconnectCallback);
    }

    @Override
    public void onUserInteraction(){
        resetDisconnectTimer();
    }

    @Override
    public void onResume() {
        super.onResume();
        resetDisconnectTimer();
    }

    @Override
    public void onStop() {
        super.onStop();
        stopDisconnectTimer();
    }
}
查看更多
骚的不知所云
5楼-- · 2019-01-01 09:01

During my Search I found a lot of answers but this is the best answer I got. But limitation of this code is that it works only for activity not for whole application. Take this as a reference.

myHandler = new Handler();
myRunnable = new Runnable() {
    @Override
    public void run() {
        //task to do if user is inactive

    }
};
@Override
public void onUserInteraction() {
    super.onUserInteraction();
    myHandler.removeCallbacks(myRunnable);
    myHandler.postDelayed(myRunnable, /*time in milliseconds for user inactivity*/);
}

for e.g you used 8000, the task will be done after 8 seconds of user inactivity.

查看更多
深知你不懂我心
6楼-- · 2019-01-01 09:03

I had similar situation to the SO question, where i needed to track the user inactivity for 1 minute then redirect the user to start Activity, i needed also to clear the activity stack.

Based on @gfrigon answer i come up with this solution.

ActionBar.java

public abstract class ActionBar extends AppCompatActivity {

    public static final long DISCONNECT_TIMEOUT = 60000; // 1 min

    private final MyHandler mDisconnectHandler = new MyHandler(this);

    private Context mContext;


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mContext = this;
    }



    /*
    |--------------------------------------------------------------------------
    | Detect user inactivity in Android
    |--------------------------------------------------------------------------
    */

    // Static inner class doesn't hold an implicit reference to the outer class

    private static class MyHandler extends Handler {

        // Using a weak reference means you won't prevent garbage collection

        private final WeakReference<ActionBar> myClassWeakReference;

        public MyHandler(ActionBar actionBarInstance) {

            myClassWeakReference = new WeakReference<ActionBar>(actionBarInstance);
        }

        @Override
        public void handleMessage(Message msg) {

            ActionBar actionBar = myClassWeakReference.get();

            if (actionBar != null) {
                // ...do work here...
            }
        }
    }


    private Runnable disconnectCallback = new Runnable() {

        @Override
        public void run() {

            // Perform any required operation on disconnect

            Intent startActivity = new Intent(mContext, StartActivity.class);

            // Clear activity stack

            startActivity.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

            startActivity(startActivity);
        }
    };

    public void resetDisconnectTimer() {

        mDisconnectHandler.removeCallbacks(disconnectCallback);
        mDisconnectHandler.postDelayed(disconnectCallback, DISCONNECT_TIMEOUT);
    }

    public void stopDisconnectTimer() {

        mDisconnectHandler.removeCallbacks(disconnectCallback);
    }

    @Override
    public void onUserInteraction(){

        resetDisconnectTimer();
    }

    @Override
    public void onResume() {

        super.onResume();
        resetDisconnectTimer();
    }

    @Override
    public void onStop() {

        super.onStop();
        stopDisconnectTimer();
    }
}

Complementary resources

Android: Clear Activity Stack

This Handler class should be static or leaks might occur

查看更多
余生无你
7楼-- · 2019-01-01 09:04

Best thing is to handle this across your whole app (assuming you have multiple activities) by registering AppLifecycleCallbacks in the Application calss. You can use registerActivityLifecycleCallbacks() in the Application class with the following callbacks (I recommend creating an AppLifecycleCallbacks class that extends the ActivityLifecycleCallbacks):

public interface ActivityLifecycleCallbacks {
    void onActivityCreated(Activity activity, Bundle savedInstanceState);
    void onActivityStarted(Activity activity);
    void onActivityResumed(Activity activity);
    void onActivityPaused(Activity activity);
    void onActivityStopped(Activity activity);
    void onActivitySaveInstanceState(Activity activity, Bundle outState);
    void onActivityDestroyed(Activity activity);
}
查看更多
登录 后发表回答