Как определить неактивность пользователя в Android

Пользователь запускает мое приложение и входит в систему.
Выбирает тайм-аут сеанса равным 5 минутам.
Выполняет некоторые операции с приложением. (все на переднем плане)
Теперь пользователь переводит Myapp в фоновый режим и запускает какое-то другое приложение.
----> Запускается таймер обратного отсчета и пользователь выходит из системы через 5 минут
ИЛИ пользователь выключает экран. < br> ----> Запускается таймер обратного отсчета и пользователь выходит из системы через 5 минут

Мне нужно такое же поведение, даже когда приложение находится на переднем плане, но пользователь не взаимодействует с приложением в течение длительного времени, скажем, 6-7 минут. Предположим, что экран включен все время. Я хочу определить тип бездействия пользователя (отсутствие взаимодействия с приложением, даже если оно находится на переднем плане) и запустить мой таймер обратного отсчета.


person Akh    schedule 17.11.2010    source источник
comment
Могли бы вы всегда включать этот таймер и сбрасывать его всякий раз, когда пользователь что-то делает?   -  person Kyle P    schedule 18.11.2010


Ответы (15)


Я нашел довольно простое решение, основанное на ответе Фредрика Валлениуса. Это базовый класс деятельности, который необходимо расширить на все виды деятельности.

public class MyBaseActivity extends Activity {

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


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

    private static 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();
    }
}
person gfrigon    schedule 18.09.2012
comment
Это создаст несколько экземпляров Handler и Runnable для каждого созданного Activity. Если мы преобразуем эти два члена в static, этого можно будет избежать. Кроме того, не могли бы вы сказать мне, почему вы звонили stopDisconnectTimer() через onStop()? - person Gaurav Bhor; 27.08.2014
comment
@Gaurav В моем случае это реализовано только в одном действии (поэтому я не заметил проблемы с модификатором static). Что касается onStop(), насколько я помню, я вызываю onBackPressed(), чтобы вернуться к экрану входа в систему в обратном вызове отключения, который, в свою очередь, вызывает метод onStop(). Когда пользователь возвращается к экрану входа в систему вручную, нажав назад, таймер также должен быть остановлен, поэтому stopDisconnectTimer() в onStop(). Я предполагаю, что эта часть зависит от ваших потребностей и реализации. - person gfrigon; 27.08.2014
comment
@gfrigon можно ли перенаправить пользователя на активность входа? - person Apostrofix; 12.11.2015
comment
@Apostrifix, конечно можно. В моем случае было только одно действие: достаточно было вызова onBackPressed(). Если в вашем стеке несколько действий, вам просто нужно создать намерение на этот счет. Вы можете посмотреть следующий ответ, чтобы очистить задачу Activity (и предотвратить повторное подключение пользователей на спине): stackoverflow.com/questions/7075349/ - person gfrigon; 13.11.2015
comment
Отличная работа! Я добавил геттер и сеттер для runnable, а затем установил их в расширяющемся классе по мере необходимости, используя метод onCreate ... отлично, еще раз спасибо. - person CrandellWS; 04.06.2016
comment
Это работает, даже когда приложение используется. Как я могу это преодолеть? - person Aparajita Sinha; 15.02.2017
comment
@ gfrigon .. Вышеуказанные методы работают нормально после входа в систему и работают. Предположим, что в перерывах между рабочими действиями, если мы открываем другое приложение, таймер останавливается. на этот раз также необходимо средство автоматического выхода из системы. что нам нужно делать? Я пробовал использовать onPause с расписанием ручного таймера, но это влияет на тайм-аут регулярной функциональности. вы можете что-нибудь подсказать? - person harikrishnan; 12.10.2017
comment
@harikrishnan Предлагаю прочитать о жизненном цикле активности: developer.android.com / руководство / компоненты / мероприятия /. Возможно, вы захотите привязать запуск и остановку таймера в разных местах жизненного цикла вашей активности. Возможно, вы захотите добавить другой таймер, который отслеживает время, в течение которого ваше приложение не находится в предварительном режиме (время между onPause и onResume) и выходит из системы на onResume, если ваш таймер истек. Если вам нужна более конкретная поддержка, вы можете задать вопрос с подробным описанием проблемы. - person gfrigon; 20.10.2017
comment
@GauravBhor, если мы сделаем Handler и Runnable статическими, как мы можем создать новые Intent(CurrentActivity.this, MainActivity.class) и startActivity(intent) из Runnable, поскольку на CurrentActivity.this и startActivity() нельзя ссылаться из статического контекста? - person Tur1ng; 11.01.2018
comment
@MJM вы можете подключить отпечатки к методам жизненного цикла (onStop, onPause, onResume, onStart), чтобы увидеть, что вызывается, когда вы блокируете и разблокируете свое устройство. Если какой-либо из них вызывается при блокировке устройства, вы можете проверить, истек ли срок действия вашего таймера, прежде чем вызывать resetDisconnectTimer (); - person gfrigon; 05.06.2018
comment
Как насчет расписания каждые 5 минут для проверки последнего взаимодействия с пользователем (этим можно управлять, сохраняя временную метку, полученную от onUserInteraction). И вы избегаете многократных вызовов для сброса счетчика / обработчика - person rafaelasguerra; 02.10.2019
comment
в Android 8 OREO это вызывает отправку сообщения обработчику при ошибке мертвого потока - person appukrb; 22.09.2020

Я не знаю, как отслеживать бездействие, но есть способ отслеживать активность пользователей. Вы можете поймать обратный вызов onUserInteraction() в ваших действиях, который вызывается каждый раз, когда пользователь выполняет какое-либо взаимодействие с приложением. Я бы посоветовал сделать что-то вроде этого:

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

Если ваше приложение содержит несколько действий, почему бы не поместить этот метод в абстрактный суперкласс (расширяющий Activity), а затем попросить все ваши действия расширить его.

person Fredrik Wallenius    schedule 17.11.2010
comment
Да, это один из способов сделать это ... но в моем приложении 30 различных действий, и когда пользователь активен, взаимодействие с ним будет слишком много ... так что каждый раз сброс таймера будет дорогостоящей операцией ... в худшем случае - от 50 до 60 раз в минуту. - person Akh; 18.11.2010
comment
Я не рассчитал время, но я бы сказал, сбросив таймер, как этот lastInteraction = System.currentTimeMillis (); займет, скажем, 2 мс. Делайте это 60 раз в минуту, и вы потеряете 120 мс. Из 60000. - person Fredrik Wallenius; 18.11.2010
comment
Фредрик ... Я также использую ваше предложение, чтобы встретить этот сценарий .. Максимальное время ожидания экрана на устройстве установлено на 30 минут. MyApp shd timeout через 15 минут ... Если пользователь ничего не трогает на экране более 1 минуты, я запускаю 15-минутный таймер выхода из системы .... В этом случае я бы проверил разницу (lastInteractionTime и System.currentTimeMills ( )) больше 1 мин ... потом огонь .. - person Akh; 18.11.2010
comment
Однако onUserInteraction () не вызывается в некоторых случаях (диалоги не вызывают его и прокручиваются в счетчиках), есть ли обходной путь для этих ситуаций? - person AndroidNoob; 25.04.2014
comment
не могли бы вы поделиться своим MyTimerClass? - person Sibelius Seraphini; 20.06.2016
comment
Какая реализация для MyTimerClass - person McSullivan; 04.10.2016
comment
Вы можете поделиться реализацией MyTimerClass? - person Vincent_Paing; 28.04.2018
comment
Отличный вклад! Это то, что я искал. Спасибо!! - person Oscar Ordoñez Mego; 09.04.2019
comment
не следует ли вам вызывать super.onUserInteraction (); ? - person Mike W; 15.07.2019
comment
Это сработало для меня, это может не сбрасывать таймер для диалогов и т. Д., Но если пользователь тратит 5 минут, глядя на диалог, у вас есть более серьезные проблемы. Я даже не добавлял его ко всем видам деятельности, только к основным, по которым часто проходят, и к тем, где они, вероятно, будут проводить больше всего времени. - person LordWabbit; 25.11.2020

Я думаю, вам следует использовать этот код, это для 5-минутного тайм-аута сеанса простоя: ->

Handler handler;
Runnable r;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    handler = new Handler();
    r = new Runnable() {

       @Override
       public void run() {
            // TODO Auto-generated method stub
            Toast.makeText(MainActivity.this, "user is inactive from last 5 minutes",Toast.LENGTH_SHORT).show();
        }
    };
    startHandler();
}
@Override
public void onUserInteraction() {
     // TODO Auto-generated method stub
     super.onUserInteraction();
     stopHandler();//stop first and then start
     startHandler();
}
public void stopHandler() {
    handler.removeCallbacks(r);
}
public void startHandler() {
    handler.postDelayed(r, 5*60*1000); //for 5 minutes 
}
person Pradeep Gupta    schedule 01.02.2017
comment
Вы спасли мою жизнь с помощью onUserInteraction - person codezombie; 05.12.2017

public class MyApplication extends Application {
      private int lastInteractionTime;
      private Boolean isScreenOff = false; 
      public void onCreate() {
        super.onCreate();
        // ......   
        startUserInactivityDetectThread(); // start the thread to detect inactivity
        new ScreenReceiver();  // creating receive SCREEN_OFF and SCREEN_ON broadcast msgs from the device.
      }

      public void startUserInactivityDetectThread() {
        new Thread(new Runnable() {
          @Override
          public void run() {
            while(true) {
              Thread.sleep(15000); // checks every 15sec for inactivity
              if(isScreenOff || getLastInteractionTime()> 120000 ||  !isInForeGrnd)
                {
                  //...... means USER has been INACTIVE over a period of
                  // and you do your stuff like log the user out 
                }
              }
          }
        }).start();
      }

      public long getLastInteractionTime() {
        return lastInteractionTime;
      }

      public void setLastInteractionTime(int lastInteractionTime) {
        this.lastInteractionTime = lastInteractionTime;
      }

      private class ScreenReceiver extends BroadcastReceiver {

        protected ScreenReceiver() {
           // register receiver that handles screen on and screen off logic
           IntentFilter filter = new IntentFilter();
           filter.addAction(Intent.ACTION_SCREEN_ON);
           filter.addAction(Intent.ACTION_SCREEN_OFF);
           registerReceiver(this, filter);
        }

        @Override
        public void onReceive(Context context, Intent intent) {
          if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
            isScreenOff = true;
          } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
            isScreenOff = false;
          }
        }
      }
    }

isInForeGrnd ===> логика здесь не показана, так как она выходит за рамки вопроса

Вы можете разбудить блокировку процессора, используя код устройства ниже:

  if(isScreenOff || getLastInteractionTime()> 120000 ||  !isInForeGrnd)
    {
      //...... means USER has been INACTIVE over a period of
      // and you do your stuff like log the user out 

      PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);

      boolean isScreenOn = pm.isScreenOn();
      Log.e("screen on.................................", "" + isScreenOn);

      if (isScreenOn == false) {

        PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "MyLock");

        wl.acquire(10000);
        PowerManager.WakeLock wl_cpu = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyCpuLock");

        wl_cpu.acquire(10000);
      }
    }
person Akh    schedule 18.11.2010
comment
@Nappy: Тогда объясните, как это правильно делать. Ваш комментарий расплывчатый и нерешительный. - person Akh; 03.05.2011
comment
@AKh: Другие ответы уже показывают возможности. В вашем решении я не вижу никакой пользы от опроса каждые 15 секунд. Это будет иметь такой же эффект, как если бы вы запускали таймер на ACTION_SCREEN_OFF со случайной длительностью от 0 до 15 секунд. Это просто не имеет смысла .. - person Nappy; 03.05.2011
comment
@Nappy: каждые 15 секунд я проверяю не только SCREEN_ON или SCREEN_OFF, но также время последнего взаимодействия пользователя и статус переднего плана приложения. Основываясь на этих трех факторах, я принимаю логическое решение о том, насколько активно пользователь взаимодействует с приложением. - person Akh; 03.05.2011
comment
Пожалуйста, заполните свой комментарий. .... если ваш isScreenof логический? А также необходимо учитывать статус приложения. - person Akh; 04.05.2011
comment
Для меня это имело бы смысл, если бы вы только сбросили таймер в onUserInteraction (ответ Фредрикса), если ваше логическое значение isScreenOff истинно, и полностью пропустите часть опроса. Если я правильно прочитал ваш последний комментарий, вы пропустили важную часть в приведенном выше коде? - person Nappy; 04.05.2011
comment
Я обновил код сейчас. Надеюсь, теперь все выглядит лучше. Если нет, дайте мне знать. - person Akh; 04.05.2011
comment
поэтому вы все еще обновляете lastInteractionTime в onUserInteraction, поэтому вам не нужно сбрасывать таймер, что, по вашему мнению, намного дороже. хорошо - я понял. Я был сбит с толку, потому что в вашем коде вы опрашивали только логическое значение screenOff, для которого опрос не нужен. - person Nappy; 04.05.2011
comment
Этот код полон ошибок, некоторые переменные не инициализируются. - person Big.Child; 05.03.2013
comment
SCREEN_ON или SCREEN_OFF могут произойти, когда пользователь получит пропущенный вызов даже, поэтому вы должны предоставить код для isInForeGrnd - person Chathura Wijesinghe; 20.01.2014

Не существует концепции «бездействия пользователя» на уровне ОС, за исключением широковещательных рассылок ACTION_SCREEN_OFF и ACTION_USER_PRESENT. Вам нужно будет каким-то образом определить «бездействие» в вашем собственном приложении.

person CommonsWare    schedule 17.11.2010

В моем базовом классе деятельности я создал защищенный класс:

protected class IdleTimer
{
    private Boolean isTimerRunning;
    private IIdleCallback idleCallback;
    private int maxIdleTime;
    private Timer timer;

    public IdleTimer(int maxInactivityTime, IIdleCallback callback)
    {
        maxIdleTime = maxInactivityTime;
        idleCallback = callback;
    }

    /*
     * creates new timer with idleTimer params and schedules a task
     */
    public void startIdleTimer()
    {
        timer = new Timer();            
        timer.schedule(new TimerTask() {

            @Override
            public void run() {             
                idleCallback.inactivityDetected();
            }
        }, maxIdleTime);
        isTimerRunning = true;
    }

    /*
     * schedules new idle timer, call this to reset timer
     */
    public void restartIdleTimer()
    {
        stopIdleTimer();
        startIdleTimer();
    }

    /*
     * stops idle timer, canceling all scheduled tasks in it
     */
    public void stopIdleTimer()
    {
        timer.cancel();
        isTimerRunning = false;
    }

    /*
     * check current state of timer
     * @return boolean isTimerRunning
     */
    public boolean checkIsTimerRunning()
    {
        return isTimerRunning;
    }
}

protected interface IIdleCallback
{
    public void inactivityDetected();
}

Итак, в методе onResume вы можете указать действие в обратном вызове, что вы хотите с ним делать ...

idleTimer = new IdleTimer(60000, new IIdleCallback() {
            @Override
            public void inactivityDetected() {
                ...your move...
            }
        });
        idleTimer.startIdleTimer();
person divide by zero    schedule 16.01.2013
comment
как проверить, что пользователь неактивен ?? какой-либо ввод из системы? - person MohsinSyd; 19.06.2014

Во время поиска я нашел много ответов, но это лучший ответ, который я получил. Но ограничение этого кода в том, что он работает только для активности, а не для всего приложения. Возьмите это как ссылку.

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*/);
}

например, вы использовали 8000, задача будет выполнена через 8 секунд бездействия пользователя.

person A_rmas    schedule 23.03.2016

Бездействие пользователя можно обнаружить с помощью метода переопределения onUserInteraction() в android

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

    }

Вот пример кода выхода (HomeActivity -> LoginActivity) через 3 минуты, когда пользователь неактивен.

public class HomeActivity extends AppCompatActivity {

    private static String TAG = "HomeActivity";
    private Handler handler;
    private Runnable r;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);


        handler = new Handler();
        r = new Runnable() {

            @Override
            public void run() {

                Intent intent = new Intent(getApplicationContext(), LoginActivity.class);
                startActivity(intent);
                Log.d(TAG, "Logged out after 3 minutes on inactivity.");
                finish();

                Toast.makeText(HomeActivity.this, "Logged out after 3 minutes on inactivity.", Toast.LENGTH_SHORT).show();
            }
        };

        startHandler();

    }

    public void stopHandler() {
        handler.removeCallbacks(r);
        Log.d("HandlerRun", "stopHandlerMain");
    }

    public void startHandler() {
        handler.postDelayed(r, 3 * 60 * 1000);
        Log.d("HandlerRun", "startHandlerMain");
    }

    @Override
    public void onUserInteraction() {
        super.onUserInteraction();
        stopHandler();
        startHandler();
    }

    @Override
    protected void onPause() {

        stopHandler();
        Log.d("onPause", "onPauseActivity change");
        super.onPause();

    }

    @Override
    protected void onResume() {
        super.onResume();
        startHandler();

        Log.d("onResume", "onResume_restartActivity");

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        stopHandler();
        Log.d("onDestroy", "onDestroyActivity change");

    }

}
person damith alahakoon    schedule 24.08.2018

Вот полное решение, которое обрабатывает бездействие пользователя через несколько минут (например, 3 минуты). Это решает общие проблемы, такие как переход активности на передний план, когда приложение находится в фоновом режиме по истечении времени ожидания.

Во-первых, мы создаем BaseActivity, которую могут расширять все остальные Activity.

Это код BaseActivity.

package com.example.timeout;

import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.view.Window;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;


import javax.annotation.Nullable;

public class BaseActivity extends AppCompatActivity implements LogoutListener {

    private Boolean isUserTimedOut = false;
    private static Dialog mDialog;



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

        ((TimeOutApp) getApplication()).registerSessionListener(this);
        ((TimeOutApp) getApplication()).startUserSession();

    }

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


    }

    @Override
    protected void onResume() {
        super.onResume();

        if (isUserTimedOut) {
            //show TimerOut dialog
            showTimedOutWindow("Time Out!", this);

        } else {

            ((TimeOutApp) getApplication()).onUserInteracted();

        }

    }

    @Override
    public void onSessionLogout() {


        isUserTimedOut = true;

    }


    public void showTimedOutWindow(String message, Context context) {


        if (mDialog != null) {
            mDialog.dismiss();
        }
        mDialog = new Dialog(context);


        mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        mDialog.setContentView(R.layout.dialog_window);

        mDialog.setCancelable(false);
        mDialog.setCanceledOnTouchOutside(false);

        TextView mOkButton = (TextView) mDialog.findViewById(R.id.text_ok);
        TextView text_msg = (TextView) mDialog.findViewById(R.id.text_msg);

        if (message != null && (!TextUtils.isEmpty(message)) && (!message.equalsIgnoreCase("null"))) {
            text_msg.setText(message);

        }


        mOkButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if (mDialog != null){

                    mDialog.dismiss();

                    Intent intent = new Intent(BaseActivity.this, LoginActivity.class);
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
                    startActivity(intent);

                    finish();
                }


            }
        });

        if(!((Activity) context).isFinishing())
        {
            //show dialog
            mDialog.show();
        }

    }

}

Затем мы создаем интерфейс для нашего «Слушателя выхода».

package com.example.timeout;

public interface LogoutListener {

    void onSessionLogout();

}

Наконец, мы создаем класс Java, который расширяет «Приложение»

package com.example.timeout;

import android.app.Application;

import java.util.Timer;
import java.util.TimerTask;

public class TimeOutApp extends Application {

    private LogoutListener listener;
    private Timer timer;
    private static final long INACTIVE_TIMEOUT = 180000; // 3 min


    public void startUserSession () {
        cancelTimer ();

        timer = new Timer ();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {

                listener.onSessionLogout ();

            }
        }, INACTIVE_TIMEOUT);

    }

    private void cancelTimer () {
        if (timer !=null) timer.cancel();
    }

    public void registerSessionListener(LogoutListener listener){
        this.listener = listener;
    }

    public void onUserInteracted () {
        startUserSession();
    }


}

Примечание. Не забудьте добавить класс TimeOutApp в тег приложения в файле манифеста.

<application
        android:name=".TimeOutApp">
        </application>
person Oyewo Remi    schedule 15.09.2019

Обработка времени ожидания взаимодействия с пользователем в KOTLIN:

     //Declare handler
      private var timeoutHandler: Handler? = null
      private var interactionTimeoutRunnable: Runnable? = null

 override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.activity_aspect_ratio)

       //Initialise handler
      timeoutHandler =  Handler();
      interactionTimeoutRunnable =  Runnable {
         // Handle Timeout stuffs here
          }

      //start countdown
      startHandler()
}

// reset handler on user interaction
override fun onUserInteraction() {
      super.onUserInteraction()
      resetHandler()
}

 //restart countdown
fun resetHandler() {
      timeoutHandler?.removeCallbacks(interactionTimeoutRunnable);
      timeoutHandler?.postDelayed(interactionTimeoutRunnable, 10*1000); //for 10 second

}

 // start countdown
fun startHandler() {
    timeoutHandler?.postDelayed(interactionTimeoutRunnable, 10*1000); //for 10 second
}
person Hitesh Sahu    schedule 22.01.2019

Я думаю, что это нужно, комбинируя таймер с временем последней активности.

Ну вот так:

  1. В onCreate (Bundle savedInstanceState) запустите таймер, скажем, 5 минут

  2. В onUserInteraction () просто сохраните текущее время

Пока все довольно просто.

Теперь, когда таймер всплывает, сделайте вот так:

  1. Возьмите текущее время и вычтите сохраненное время взаимодействия, чтобы получить timeDelta
  2. Если timeDelta> = 5 минут, все готово.
  3. Если timeDelta ‹, то 5 минут снова запускают таймер, но на этот раз используйте 5 минут - сохраненное время. Другими словами, 5 минут до последнего взаимодействия.
person Robert Wiebe    schedule 06.11.2014

У меня была аналогичная ситуация с вопросом SO, где мне нужно было отслеживать бездействие пользователя в течение 1 минуты, а затем перенаправлять пользователя для запуска Activity, мне также нужно было очистить стек активности.

Основываясь на ответе @gfrigon, я придумал это решение.

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();
    }
}

Дополнительные ресурсы

Android: очистить стек действий

Этот класс Handler должен быть статическим, иначе могут возникнуть утечки.

person chebaby    schedule 13.07.2018

Лучше всего справиться с этим во всем приложении (при условии, что у вас несколько действий), зарегистрировав AppLifecycleCallbacks в приложении calss. Вы можете использовать registerActivityLifecycleCallbacks() в классе Application со следующими обратными вызовами (я рекомендую создать класс AppLifecycleCallbacks, который расширяет 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);
}
person box    schedule 05.09.2018

open class SubActivity : AppCompatActivity() {
    var myRunnable:Runnable
    private var myHandler = Handler()

    init {
        myRunnable = Runnable{
            toast("time out")
            var intent = Intent(this, MainActivity::class.java)
            startActivity(intent)

        }
    }

    fun toast(text: String) {
        runOnUiThread {
            val toast = Toast.makeText(applicationContext, text, Toast.LENGTH_SHORT)
            toast.show()
        }
    }

   override fun onUserInteraction() {
        super.onUserInteraction();
        myHandler.removeCallbacks(myRunnable)
        myHandler.postDelayed(myRunnable, 3000)
    }

    override fun onPause() {
        super.onPause()
        myHandler.removeCallbacks(myRunnable)
    }

    override fun onResume() {
            super.onResume()
            myHandler.postDelayed(myRunnable, 3000)
    }
}

Расширьте свою деятельность с помощью

YourActivity:SubActivity(){}

чтобы перейти к MainActivity, когда пользователь неактивен после 3000 миллисекунд на YourActivity

Я использовал предыдущий ответ и преобразовал его в котлин.

person Tom Peak    schedule 30.10.2019

person    schedule
comment
Это основа решения, остальное можно изменить в зависимости от ваших конкретных потребностей и сложности архитектуры приложения! Спасибо за ответ! - person Hack06; 08.01.2018
comment
Как применить это в классе приложения - person Gaju Kollur; 24.04.2018
comment
Лаконичное решение! Большое спасибо, чувак! - person Damercy; 28.04.2021