So erkennen Sie Benutzerinaktivität in Android


101

Der Benutzer startet meine App und meldet sich an. Das
Sitzungszeitlimit beträgt 5 Minuten.
Führt einige Operationen in der App aus. (alles im Vordergrund)
Jetzt bringt der Benutzer Myapp in den Hintergrund und startet eine andere App.
----> Der Countdown-Timer startet und meldet den Benutzer nach 5 Minuten ab
ODER der Benutzer schaltet den Bildschirm aus.
----> Der Countdown-Timer startet und meldet den Benutzer nach 5 Minuten ab

Ich möchte das gleiche Verhalten, auch wenn die App im Vordergrund steht, der Benutzer jedoch längere Zeit nicht mit der App interagiert, z. B. 6-7 Minuten. Angenommen, der Bildschirm ist ständig eingeschaltet. Ich möchte eine Art von Inaktivität des Benutzers erkennen (keine Interaktion mit der App, obwohl die App im Vordergrund steht) und meinen Countdown-Timer starten.


1
Könnten Sie diesen Timer immer laufen lassen und zurücksetzen, wenn der Benutzer etwas tut?
Kyle P

Antworten:


111

Ich habe eine Lösung gefunden, die ich aufgrund der Antwort von Fredrik Wallenius recht einfach finde. Dies ist eine Basisaktivitätsklasse, die um alle Aktivitäten erweitert werden muss.

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
Dadurch werden mehrere Instanzen von Handlerund Runnablefür jede Activityerstellte erstellt. Wenn wir diese beiden Mitglieder in konvertieren static, wird dies vermieden. Auch könnten Sie mir sagen , warum Sie angerufen haben stopDisconnectTimer()in onStop()`?
Gaurav Bhor

@Gaurav In meinem Fall ist dies nur in einer Aktivität implementiert (daher habe ich das Problem mit dem staticModifikator nicht erkannt). Soweit onStop()ich mich erinnere, rufe ich onBackPressed()auf, um zu einem Anmeldebildschirm im Trennungsrückruf zurückzukehren, der wiederum die onStop()Methode aufruft . Wenn der Benutzer manuell zum Anmeldebildschirm zurückkehrt, muss durch Zurückdrücken auch der Timer gestoppt werden, also der stopDisconnectTimer()Eingang onStop(). Ich denke, dieser Teil hängt von Ihren Anforderungen und Ihrer Implementierung ab.
Gfrigon

@gfrigon ist es möglich, den Benutzer zur Anmeldeaktivität umzuleiten?
Apostrofix

@Apostrifix, natürlich ist es möglich. In meinem Fall gab es nur eine Aktivität: onBackPressed()Vas ausreichend anrufen . Wenn Sie mehr als eine Aktivität in Ihrem Stapel haben, müssen Sie nur eine Absicht für diese Angelegenheit erstellen. Sie können sich die folgende Antwort ansehen, um die Aktivitätsaufgabe zu löschen (und zu verhindern, dass Benutzer auf einer Rückseite erneut eine Verbindung herstellen): stackoverflow.com/questions/7075349/…
gfrigon

Gute Arbeit! Ich habe Getter und Setter für die ausführbare Datei hinzugefügt und sie dann nach Bedarf mit der onCreate-Methode in der Erweiterungsklasse festgelegt ... perfekt, nochmals vielen Dank.
CrandellWS

90

Ich kenne keine Möglichkeit, Inaktivität zu verfolgen, aber es gibt eine Möglichkeit, Benutzeraktivitäten zu verfolgen. Sie können einen Rückruf abfangen, der onUserInteraction()in Ihren Aktivitäten aufgerufen wird und jedes Mal aufgerufen wird, wenn der Benutzer eine Interaktion mit der Anwendung ausführt. Ich würde vorschlagen, so etwas zu tun:

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

Wenn Ihre App mehrere Aktivitäten enthält, fügen Sie diese Methode in eine abstrakte Superklasse (Erweiterung Activity) ein und lassen Sie sie dann von allen Aktivitäten erweitern.


1
Ja, das ist eine Möglichkeit ... aber meine App hat 30 verschiedene Aktivitäten und es würde zu viel Interaktion geben, wenn der Benutzer aktiv ist ... also jedes Mal, wenn der Timer zurückgesetzt wird, ist dies eine kostspielige Operation ... was bei der Der schlimmste Fall kann 50 bis 60 Mal pro Minute sein.
Akh

3
Ich habe es nicht zeitlich festgelegt, aber ich würde sagen, einen Timer wie diesen zurückzusetzen lastInteraction = System.currentTimeMillis (); würde zum Beispiel 2 ms dauern. Tun Sie es 60 Mal pro Minute und Sie "verlieren" 120 ms. Von 60000.
Fredrik Wallenius

1
Fredrik ... Ich verwende auch Ihren Vorschlag, um dieses Szenario zu erfüllen. Das Bildschirm-Timeout ist auf dem Gerät auf maximal 30 Minuten eingestellt. MyApp shd timeout nach 15 min ... Wenn der Benutzer länger als 1 min nichts auf dem Bildschirm berührt, starte ich den 15min Logout-Timer .... In diesem Fall würde ich den Unterschied überprüfen (lastInteractionTime und System.currentTimeMills ( )) ist mehr als 1 min ... dann feuern ..
Akh

3
onUserInteraction () wird in einigen Fällen jedoch nicht aufgerufen (Dialoge rufen es nicht auf und scrollen in Spinnern). Gibt es eine Problemumgehung für diese Situationen?
AndroidNoob

Könnten Sie Ihre MyTimerClass teilen?
Sibelius Seraphini

19

Ich denke, Sie sollten mit diesem Code gehen, dies ist für 5 Minuten Leerlaufsitzung Timeout: ->

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 
}

Sie haben mein Leben mit 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 ===> Logik wird hier nicht angezeigt, da sie nicht in Frage kommt

Sie können die Sperre für die CPU mithilfe des folgenden Gerätecodes aktivieren.

  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
@ Windel: Dann erklären Sie bitte den richtigen Weg, dies zu tun. Ihr Kommentar ist vage und unentschlossen.
Akh

2
@AKh: Die anderen Antworten zeigen bereits die Möglichkeiten. In Ihrer Lösung kann ich keinen Nutzen aus einer Abfrage alle 15 Sekunden ziehen. Dies hätte den gleichen Effekt, wenn Sie einen Timer für "ACTION_SCREEN_OFF" mit einer zufälligen Dauer von 0 bis 15 Sekunden starten. Das macht einfach keinen Sinn ..
Windel

1
@ Windel: Alle 15 Sekunden überprüfe ich nicht nur SCREEN_ON oder SCREEN_OFF, sondern auch die letzte Interaktionszeit des Benutzers und den App-Vordergrundstatus. Basierend auf diesen drei Faktoren treffe ich eine logische Entscheidung darüber, wie aktiv der Benutzer mit der App interagiert.
Akh

Bitte vervollständigen Sie Ihren Kommentar. .... "wenn dein isScreenof boolean ist?" Und auch der App-Foregrnd-Status muss berücksichtigt werden.
Akh

1
Dieser Code ist voller Fehler, einige Variablen werden nicht initialisiert.
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));
}

Dies ist die Basis der Lösung. Der Rest kann je nach Ihren speziellen Anforderungen und der Komplexität der Anwendungsarchitektur geändert werden. Danke für die Antwort!
Hack06

Wie man dies in der Anwendungsklasse anwendet
Gaju Kollur

6

Es gibt kein Konzept für "Benutzerinaktivität" auf Betriebssystemebene, abgesehen von ACTION_SCREEN_OFFund ACTION_USER_PRESENTBroadcasts. Sie müssen "Inaktivität" irgendwie in Ihrer eigenen Anwendung definieren.


6

Sogar Sie können Ihre Anforderungen mit @ gfrigon- oder @ AKK- Lösungen verwalten.

Aber hier ist Timer und Handler kostenlose Lösung dafür. Ich habe bereits eine gut verwaltete Timer-Lösung dafür. Aber ich habe erfolgreich Timer und Handler freie Lösung implementiert.

Zuerst sage ich Ihnen, was Sie verwalten müssen, wenn Sie Timer oder Handler verwenden.

  • Wenn Ihre App vom Benutzer oder von einem Optimierer beendet wird, wird Ihre App niemals automatisch abgemeldet, da alle Ihre Rückrufe zerstört werden. ( Alarmmanager oder Service verwalten? )
  • Ist es gut, in jeder Basisklasse einen Timer zu haben? Sie erstellen viele Threads, um nur den Abmeldevorgang aufzurufen ( statischen Handler oder Timer auf App-Ebene verwalten? ).
  • Was passiert, wenn sich der Benutzer im Hintergrund befindet? Ihr Handler startet die Anmeldeaktivität, wenn der Benutzer andere Arbeiten außerhalb Ihrer App ausführt. ( App Vordergrund oder Hintergrund verwalten? ).
  • Was ist, wenn der Bildschirm automatisch ausgeht? ( Bildschirm auf Rundfunkempfänger ausschalten? )

Schließlich habe ich eine Lösung implementiert, die ist

  1. KEIN Handler oder Timer.
  2. KEIN Alarm Manager.
  3. App LifeCycle NICHT verwalten.
  4. NEIN ACTION_SCREEN_ON/ ACTION_SCREEN_OFFRundfunkempfänger.

Einfachste zuverlässige Lösung

Wir werden die Inaktivität des Benutzers nicht durch Timer beobachten, sondern die letzte Aktivitätszeit auf Benutzeraktivität überprüfen. Wenn der Benutzer das nächste Mal mit der App interagiert, überprüfe ich die letzte Interaktionszeit.

Hier ist, BaseActivity.classwas Sie von jeder Ihrer Aktivitätsklassen anstelle von erweitern LoginActivity. Sie definieren Ihre Abmeldezeit im Feld TIMEOUT_IN_MILLIdieser Klasse.

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.
    }
}

Wie ist der Zugriff auf freigegebene Einstellungen im Hauptthread bei jeder Benutzerinteraktion besser als das Aufrufen mehrerer Threads?
Nishita

@ Nishita Zum Zeitpunkt der Veröffentlichung dieser Antwort war mir dieser Nachteil nicht bekannt. Vielen Dank für den Kommentar zu meiner 1 schlechten Antwort. Sie haben Recht, das ist kein richtiger Weg, es zu tun. Ich werde diese Antwort verbergen.
Khemraj

2

In meiner Aktivitätsbasisklasse habe ich eine geschützte Klasse erstellt:

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

In der onResume- Methode können Sie also in Ihrem Rückruf eine Aktion angeben, was Sie damit tun möchten ...

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

Wie überprüfe ich, ob der Benutzer inaktiv ist? irgendwelche Eingaben vom System?
MohsinSyd

2

Während meiner Suche habe ich viele Antworten gefunden, aber dies ist die beste Antwort, die ich bekommen habe. Die Einschränkung dieses Codes besteht jedoch darin, dass er nur für Aktivitäten und nicht für die gesamte Anwendung funktioniert. Nehmen Sie dies als Referenz.

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

Wenn Sie beispielsweise 8000 verwendet haben, wird die Aufgabe nach 8 Sekunden Inaktivität des Benutzers ausgeführt.


2

Benutzerinaktivität kann mithilfe der onUserInteraction()Überschreibungsmethode in Android erkennen

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

    }

Hier ist der Beispielcode: Abmelden (HomeActivity -> LoginActivity) nach 3 Minuten, wenn der Benutzer inaktiv ist

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

Umgang mit Benutzern im Interaktionszeitlimit in 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

Hier ist eine Komplettlösung, die die Inaktivität des Benutzers nach wenigen Minuten (z. B. 3 Minuten) behandelt. Dies löst die häufigsten Probleme wie das Springen von Aktivitäten in den Vordergrund, wenn sich die App nach einer Zeitüberschreitung im Hintergrund befindet.

Zunächst erstellen wir eine BaseActivity, die alle anderen Aktivitäten erweitern können.

Dies ist der BaseActivity-Code.

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

    }

}

Als nächstes erstellen wir eine Schnittstelle für unseren "Logout Listener"

package com.example.timeout;

public interface LogoutListener {

    void onSessionLogout();

}

Schließlich erstellen wir eine Java-Klasse, die "Anwendung" erweitert.

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


}

Hinweis: Vergessen Sie nicht, die Klasse "TimeOutApp" zu Ihrem Anwendungs-Tag in Ihrer Manifest-Datei hinzuzufügen

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

0

Ich denke, es muss sein, indem der Timer mit der letzten Aktivitätszeit kombiniert wird.

Also so:

  1. Starten Sie in onCreate (Bundle savedInstanceState) einen Timer, z. B. 5 Minuten

  2. Speichern Sie in onUserInteraction () nur die aktuelle Uhrzeit

Bisher ziemlich einfach.

Nun, wenn der Timer Pop so aussieht:

  1. Nehmen Sie die aktuelle Zeit und subtrahieren Sie die gespeicherte Interaktionszeit, um timeDelta zu erhalten
  2. Wenn timeDelta> = die 5 Minuten ist, sind Sie fertig
  3. Wenn timeDelta <die 5 Minuten ist, starten Sie den Timer erneut, aber verwenden Sie diesmal 5 Minuten - die gespeicherte Zeit. Mit anderen Worten, 5 Minuten bilden die letzte Interaktion

0

Ich hatte eine ähnliche Situation wie bei der SO-Frage, bei der ich die Inaktivität des Benutzers 1 Minute lang verfolgen und dann den Benutzer umleiten musste, um die Aktivität zu starten. Außerdem musste ich den Aktivitätsstapel löschen.

Basierend auf der Antwort von @gfrigon habe ich diese Lösung gefunden.

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

Ergänzende Ressourcen

Android: Aktivitätsstapel löschen

Diese Handler-Klasse sollte statisch sein, da sonst Lecks auftreten können


0

Am besten erledigen Sie dies in Ihrer gesamten App (vorausgesetzt, Sie haben mehrere Aktivitäten), indem Sie sich AppLifecycleCallbacksim Anwendungs-Calss registrieren. Sie können registerActivityLifecycleCallbacks()in der Application-Klasse die folgenden Rückrufe verwenden (ich empfehle, eine AppLifecycleCallbacks-Klasse zu erstellen, die die ActivityLifecycleCallbacks erweitert):

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

Erweitern Sie Ihre Aktivität mit

YourActivity:SubActivity(){}

um zu MainActivity zu gelangen, wenn der Benutzer nach 3000 Millisekunden in YourActivity inaktiv ist

Ich habe eine vorherige Antwort verwendet und sie in Kotlin umgewandelt.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.