Comment détecter l'inactivité des utilisateurs dans Android


101

L'utilisateur démarre mon application et se connecte.
Sélectionne le délai d'expiration de la session à 5 minutes.
Effectue certaines opérations sur l'application. (tout au premier plan)
Maintenant, l'utilisateur met Myapp en arrière-plan et démarre une autre application.
----> Le compte à rebours démarre et déconnecte l'utilisateur après 5 minutes
OU l'utilisateur éteint l'écran.
----> Le compte à rebours démarre et déconnecte l'utilisateur après 5 minutes

Je veux le même comportement même lorsque l'application est au premier plan mais que l'utilisateur n'interagit pas avec l'application pendant une longue période, disons 6-7 minutes. Supposons que l'écran est allumé tout le temps. Je veux détecter le type d' inactivité de l' utilisateur (aucune interaction avec l'application même si l'application est au premier plan) et lancer mon compte à rebours.


1
Pourriez-vous toujours faire fonctionner cette minuterie et la réinitialiser chaque fois que l'utilisateur fait quelque chose?
Kyle P

Réponses:


112

J'ai trouvé une solution que je trouve assez simple basée sur la réponse de Fredrik Wallenius. C'est une classe d'activité de base qui doit être étendue à toutes les activités.

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

3
Cela créera plusieurs instances du Handleret Runnablepour chaque Activitycréé. Si nous convertissons ces deux membres en static, cela sera évité. Aussi, pourriez - vous me dire pourquoi vous avez appelé stopDisconnectTimer()dans onStop()`?
Gaurav Bhor

@Gaurav Dans mon cas, cela n'est implémenté que dans une seule activité (donc je n'ai pas attrapé le problème avec le staticmodificateur). Quant au onStop(), d'après ce dont je me souviens, j'appelle onBackPressed()pour revenir à un écran de connexion dans le rappel de déconnexion qui à son tour appelle la onStop()méthode. Lorsque l'utilisateur revient manuellement à l'écran de connexion, en appuyant sur retour, le chronomètre doit être arrêté ainsi que le stopDisconnectTimer()in onStop(). Je suppose que cette partie dépend de vos besoins et de votre mise en œuvre.
gfrigon

@gfrigon est-il possible de rediriger l'utilisateur vers l'activité de connexion?
Apostrofix

@Apostrifix, bien sûr, c'est possible. Dans mon cas, il n'y avait qu'une seule activité: appeler était onBackPressed()suffisant. Si vous avez plusieurs activités dans votre pile, il vous suffit de créer une intention pour cette question. Vous pouvez consulter la réponse suivante pour effacer la tâche d'activité (et empêcher les utilisateurs de se
reconnecter à l'

Bon travail! J'ai ajouté un getter et un setter pour le runnable, puis je l'ai défini dans la classe d'extension selon les besoins en utilisant la méthode onCreate ... parfait, encore une fois merci.
CrandellWS

90

Je ne connais pas un moyen de suivre l'inactivité, mais il existe un moyen de suivre l'activité des utilisateurs. Vous pouvez intercepter un rappel appelé onUserInteraction()dans vos activités qui est appelé chaque fois que l'utilisateur interagit avec l'application. Je suggérerais de faire quelque chose comme ça:

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

Si votre application contient plusieurs activités, pourquoi ne pas mettre cette méthode dans une super classe abstraite (extension Activity) et ensuite faire étendre toutes vos activités.


1
Ouais, c'est une façon de le faire ... mais mon application a 30 activités différentes et il y aurait trop d'interaction lorsque l'utilisateur est actif ... donc chaque fois que la réinitialisation de la minuterie est une opération coûteuse ... le pire des cas peut 50 à 60 fois par minute.
Akh

3
Je ne l'ai pas chronométré mais je dirais de réinitialiser une minuterie comme celle-ci lastInteraction = System.currentTimeMillis (); prendrait, disons, 2 ms. Faites-le 60 fois par minute et vous «perdez» 120 ms. Sur 60000.
Fredrik Wallenius

1
Fredrik ... J'utilise également votre suggestion pour répondre à ce scénario. Le délai d'expiration de l'écran est défini sur 30 minutes maximum sur l'appareil. MyApp shd timeout après 15 minutes ... Si l'utilisateur ne touche rien à l'écran depuis plus de 1 minute, je vais démarrer le minuteur de déconnexion de 15 minutes .... Dans ce cas, je vérifierais le différenct (lastInteractionTime et System.currentTimeMills ( )) dure plus de 1 min ... puis tirez ..
Akh

3
onUserInteraction () n'est cependant pas appelé dans certains cas (les boîtes de dialogue ne l'appellent pas et le défilement dans les filateurs) existe-t-il un contournement pour ces situations?
AndroidNoob

pourriez-vous partager votre MyTimerClass?
Sibelius Seraphini

19

Je pense que vous devriez aller avec ce code, c'est pour un délai de session inactif de 5 minutes: ->

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 
}

Vous m'avez sauvé la vie avec onUserInteraction
codezombie

10
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 ===> la logique n'est pas affichée ici car elle est hors de portée de la question

Vous pouvez réactiver le verrou du processeur en utilisant le code de l'appareil ci-dessous

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

4
@Nappy: Alors s'il vous plaît, expliquez la bonne façon de procéder. Votre commentaire est vague et indécis.
Akh

2
@AKh: Les autres réponses montrent déjà les possibilités. Dans votre solution, je ne vois aucun avantage à interroger toutes les 15 secondes. Cela aurait le même effet, car vous démarrez une minuterie sur "ACTION_SCREEN_OFF" avec une durée aléatoire de 0 à 15 secondes. Cela n'a tout simplement pas de sens ..
Nappy

1
@Nappy: Toutes les 15 secondes, je vérifie non seulement SCREEN_ON ou SCREEN_OFF, mais également l'heure de la dernière interaction de l'utilisateur et l'état de premier plan de l'application. Sur la base de ces trois facteurs, je prends une décision logique sur le degré d'activité de l'utilisateur avec l'application.
Akh

Veuillez compléter votre commentaire. .... "si votre isScreenof booléen est?" Et aussi le statut de l'application antérieure doit être pris en compte.
Akh

1
Ce code est plein d'erreurs, certaines variables ne sont pas initialisées.
Big.Child

8
@Override
public void onUserInteraction() {
    super.onUserInteraction();
    delayedIdle(IDLE_DELAY_MINUTES);
}

Handler _idleHandler = new Handler();
Runnable _idleRunnable = new Runnable() {
    @Override
    public void run() {
        //handle your IDLE state
    }
};

private void delayedIdle(int delayMinutes) {
    _idleHandler.removeCallbacks(_idleRunnable);
    _idleHandler.postDelayed(_idleRunnable, (delayMinutes * 1000 * 60));
}

C'est la base de la solution, le reste peut être modifié en fonction de vos besoins particuliers et de la complexité de l'architecture de votre application! Merci d'avoir répondu!
Hack06

Comment appliquer cela dans la classe d'application
Gaju Kollur

6

Il n'y a pas de concept d '«inactivité de l'utilisateur» au niveau du système d'exploitation, au-delà des diffusions ACTION_SCREEN_OFFet ACTION_USER_PRESENT. Vous devrez définir "inactivité" d'une manière ou d'une autre dans votre propre application.


6

Même vous pouvez gérer vos besoins avec les solutions @gfrigon ou @AKh .

Mais voici une solution gratuite Timer and Handlers pour cela. J'ai déjà une solution de minuterie bien gérée pour cela. Mais j'ai mis en œuvre avec succès la solution gratuite Timer and Handler.

Tout d'abord, je vous dis ce que vous devez gérer si vous utilisez Timer ou Handlers.

  • Si votre application est tuée par l'utilisateur ou par un optimiseur, votre application ne sera jamais déconnectée automatiquement, car tous vos rappels sont détruits. ( Gérer un gestionnaire ou un service d'alarme? )
  • Est-il bon d'avoir une minuterie dans chaque classe de base? Vous créez de nombreux threads pour simplement appeler le processus de déconnexion ( gérer le gestionnaire statique ou le minuteur au niveau de l'application? ).
  • Que faire si l'utilisateur est en arrière-plan, votre gestionnaire démarrera l'activité de connexion si l'utilisateur effectue un autre travail en dehors de votre application. ( Gérer le premier plan ou l'arrière-plan de l'application? ).
  • Et si l'écran s'éteint automatiquement. ( Gérer l'écran éteint sur le récepteur de diffusion? )

Enfin j'ai implémenté une solution qui est

  1. AUCUN gestionnaire ou minuterie.
  2. PAS de gestionnaire d'alarme.
  3. PAS gérer le cycle de vie de l'application.
  4. NO ACTION_SCREEN_ON/ ACTION_SCREEN_OFFrécepteur de diffusion.

Solution fiable la plus simple

Nous n'observerons pas l'inactivité de l'utilisateur par les minuteries plutôt que nous vérifierons l'heure de la dernière activité sur l'activité de l'utilisateur. Ainsi, lorsque l'utilisateur interagit avec l'application la prochaine fois, je vérifie l'heure de la dernière interaction.

Voici BaseActivity.classce que vous allez étendre à partir de chacune de vos classes d'activités au lieu de LoginActivity. Vous définirez votre heure de déconnexion dans le champ TIMEOUT_IN_MILLIde cette classe.

import android.content.Intent;
import android.content.SharedPreferences;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;

public class BaseActivity extends AppCompatActivity {
    public static final long TIMEOUT_IN_MILLI = 1000 * 20;
    public static final String PREF_FILE = "App_Pref";
    public static final String KEY_SP_LAST_INTERACTION_TIME = "KEY_SP_LAST_INTERACTION_TIME";

    @Override
    public void onUserInteraction() {
        super.onUserInteraction();
        if (isValidLogin())
            getSharedPreference().edit().putLong(KEY_SP_LAST_INTERACTION_TIME, System.currentTimeMillis()).apply();
        else logout();
    }

    public SharedPreferences getSharedPreference() {
        return getSharedPreferences(PREF_FILE, MODE_PRIVATE);
    }

    public boolean isValidLogin() {
        long last_edit_time = getSharedPreference().getLong(KEY_SP_LAST_INTERACTION_TIME, 0);
        return last_edit_time == 0 || System.currentTimeMillis() - last_edit_time < TIMEOUT_IN_MILLI;
    }

    public void logout() {
        Intent intent = new Intent(this, LoginActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
        startActivity(intent);
        finish();
        Toast.makeText(this, "User logout due to inactivity", Toast.LENGTH_SHORT).show();
        getSharedPreference().edit().remove(KEY_SP_LAST_INTERACTION_TIME).apply(); // make shared preference null.
    }
}

1
Comment accéder aux préférences partagées sur le thread principal à chaque interaction de l'utilisateur est-il meilleur que d'appeler plusieurs threads?
Nishita

@Nishita au moment de poster cette réponse, je n'étais pas au courant de ce désavantage. Merci d'avoir commenté ma 1 mauvaise réponse. Vous avez raison, ce n'est pas la bonne façon de le faire. Je cacherai cette réponse.
Khemraj

2

Dans ma classe de base d'activité, j'ai créé une classe protégée:

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

Donc, dans la méthode onResume - vous pouvez spécifier une action dans votre rappel ce que vous souhaitez en faire ...

idleTimer = new IdleTimer(60000, new IIdleCallback() {
            @Override
            public void inactivityDetected() {
                ...your move...
            }
        });
        idleTimer.startIdleTimer();

comment vérifier que l'utilisateur est inactif ?? une entrée du système?
MohsinSyd

2

Au cours de ma recherche, j'ai trouvé beaucoup de réponses, mais c'est la meilleure réponse que j'ai obtenue. Mais la limitation de ce code est qu'il ne fonctionne que pour l'activité et non pour l'ensemble de l'application. Prenez ceci comme référence.

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

par exemple, vous avez utilisé 8000, la tâche sera effectuée après 8 secondes d'inactivité de l'utilisateur.


2

L'inactivité de l'utilisateur peut détecter à l'aide de la onUserInteraction()méthode de remplacement dans Android

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

    }

Voici l'exemple de code, déconnexion (HomeActivity -> LoginActivity) après 3min lorsque l'utilisateur est inactif

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");

    }

}

2

Gestion de l'utilisateur en cas d'expiration du délai d'interaction dans 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
}

1

Voici une solution complète qui gère l'inactivité des utilisateurs après quelques minutes (par exemple 3 minutes). Cela résout les problèmes courants tels que l'activité sautant au premier plan lorsque l'application est en arrière-plan à l'expiration du délai.

Tout d'abord, nous créons une BaseActivity que toutes les autres activités peuvent étendre.

Il s'agit du code 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();
        }

    }

}

Ensuite, nous créons une interface pour notre "Logout Listener"

package com.example.timeout;

public interface LogoutListener {

    void onSessionLogout();

}

Enfin, nous créons une classe Java qui étend "Application"

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


}

Remarque: n'oubliez pas d'ajouter la classe "TimeOutApp" à votre balise d'application dans votre fichier manifeste

<application
        android:name=".TimeOutApp">
        </application>

0

Je pense que cela doit être en combinant la minuterie avec le dernier temps d'activité.

Alors comme ça:

  1. Dans onCreate (Bundle savedInstanceState) démarrer un minuteur, disons 5 minutes

  2. Dans onUserInteraction (), enregistrez simplement l'heure actuelle

Assez simple jusqu'à présent.

Maintenant, quand la minuterie saute, faites comme ceci:

  1. Prenez l'heure actuelle et soustrayez le temps d'interaction stocké pour obtenir l'heure
  2. Si timeDelta est> = les 5 minutes, vous avez terminé
  3. Si timeDelta est <les 5 minutes, redémarrez la minuterie, mais cette fois, utilisez 5 minutes - l'heure mémorisée. En d'autres termes, 5 minutes forment la dernière interaction

0

J'avais une situation similaire à la question SO, où je devais suivre l'inactivité de l'utilisateur pendant 1 minute, puis rediriger l'utilisateur pour démarrer l'activité, je devais également effacer la pile d'activités.

Sur la base de la réponse @gfrigon, je propose cette 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();
    }
}

Des ressources complémentaires

Android: Effacer la pile d'activités

Cette classe Handler doit être statique ou des fuites peuvent se produire


0

La meilleure chose à faire est de gérer cela dans toute votre application (en supposant que vous ayez plusieurs activités) en vous inscrivant AppLifecycleCallbacksdans les cals de l'application. Vous pouvez utiliser registerActivityLifecycleCallbacks()dans la classe Application avec les rappels suivants (je recommande de créer une classe AppLifecycleCallbacks qui étend les 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);
}

0
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)
    }
}

Prolongez votre activité avec

YourActivity:SubActivity(){}

pour accéder à MainActivity lorsque l'utilisateur est inactif après 3000 millisecondes sur YourActivity

J'ai utilisé une réponse précédente et l'ai convertie en kotlin.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.