Android'de kullanıcı hareketsizliği nasıl tespit edilir


101

Kullanıcı uygulamamı başlatır ve oturum
açar . Oturum Zaman Aşımını 5 dakika olarak seçer.
Uygulamada bazı işlemler yapıyor. (tümü ön planda)
Şimdi Kullanıcı Myapp'ı arka plana getirir ve başka bir uygulamayı başlatır.
----> Geri sayım sayacı başlar ve 5 dakika sonra kullanıcının oturumunu
kapatır VEYA kullanıcı ekranı KAPATIR.
----> Geri sayım sayacı başlar ve 5 dakika sonra kullanıcının oturumunu kapatır

Uygulama ön plandayken bile aynı davranışı istiyorum, ancak kullanıcı uygulamayla uzun süre örneğin 6-7 dakika etkileşime girmiyor. Ekranın her zaman AÇIK olduğunu varsayın. Kullanıcı hareketsizliğini tespit etmek (uygulama ön planda olmasına rağmen uygulamayla etkileşim yok) ve geri sayım zamanlayıcımı başlatmak istiyorum.


1
Bu zamanlayıcıyı her zaman çalıştırıp, kullanıcı bir şey yaptığında onu sıfırlayabilir misiniz?
Kyle P

Yanıtlar:


112

Fredrik Wallenius'un cevabına dayanarak oldukça basit bulduğum bir çözüm buldum. Bu, tüm aktiviteler tarafından genişletilmesi gereken temel bir aktivite sınıfıdır.

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
Bu, oluşturulan her biri için Handlerve öğesinin birden çok örneğini oluşturacaktır. Bu iki üyeyi dönüştürürsek bundan kaçınılacaktır. Ayrıca, aradığınız bana neden söyleyebilirdi içinde `?RunnableActivitystaticstopDisconnectTimer()onStop()
Gaurav Bhor

@Gaurav Benim durumumda, bu yalnızca bir aktivitede uygulanıyor (bu nedenle, staticdeğiştiriciyle sorunu yakalamadım ). Gelince onStop(), hatırladığım kadarıyla onBackPressed(), sırayla onStop()yöntemi çağıran bağlantı kesme geri aramasında bir giriş ekranına dönmek için arıyorum . Giriş ekranında kullanıcı döner elle geri basarak, zamanlayıcı ihtiyaçları iyi böylelikle olarak durdurulmak zaman stopDisconnectTimer()içinde onStop(). Sanırım bu kısım ihtiyaçlarınıza ve uygulamanıza bağlı.
gfrigon

@gfrigon, kullanıcıyı oturum açma etkinliğine yönlendirmek mümkün mü?
Apostrofix

@Apostrifix, Elbette mümkün. Benim durumumda tek bir aktivite vardı: vas'i onBackPressed()aramak yeterli. Yığınınızda birden fazla aktivite varsa, sadece bu konu için bir niyet oluşturmanız gerekir. Etkinlik görevini temizlemek (ve kullanıcıların arkadan yeniden bağlanmasını önlemek) için aşağıdaki yanıta bakmak isteyebilirsiniz: stackoverflow.com/questions/7075349/…
gfrigon

Harika iş! Runnable için alıcı ve ayarlayıcı ekledim ve ardından onu, onCreate yöntemini kullanarak genişletme sınıfında gerektiği gibi ayarladım ... mükemmel, tekrar teşekkür ederim.
CrandellWS

91

Hareketsizliği izlemenin bir yolunu bilmiyorum ama kullanıcı etkinliğini izlemenin bir yolu var. onUserInteraction()Aktivitelerinizde çağrılan ve kullanıcı uygulamayla herhangi bir etkileşimde bulunduğunda çağrılan bir geri aramayı yakalayabilirsiniz . Bunun gibi bir şey yapmanızı öneririm:

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

Uygulamanız birkaç etkinlik içeriyorsa, neden bu yöntemi soyut bir süper sınıfa (genişletme Activity) yerleştirip ardından tüm etkinliklerinizi genişletmiyorsunuz.


1
Evet, bunu yapmanın bir yolu bu ... ama uygulamamın 30 farklı etkinliği var ve kullanıcı aktifken çok fazla etkileşim oluyor ... bu yüzden zamanlayıcıyı her sıfırlamak pahalı bir işlem olacak ... en kötü durum dakikada 50 ila 60 kez olabilir.
Akh

3
Zamanlamadım ama bunun gibi bir zamanlayıcıyı sıfırlamayı söyleyebilirim lastInteraction = System.currentTimeMillis (); 2 ms sürer. Dakikada 60 kez yapın ve 120 ms "kaybedersiniz". Out of 60000.
Fredrik Wallenius

1
Fredrik ... Bu senaryoyu karşılamak için de sizin önerinizi kullanıyorum .. Ekran zaman aşımı cihazda maksimum 30 dakikaya ayarlandı. 15 dakikadan sonra Uygulamam shd zaman aşımına uğradı ... Kullanıcı ekranda 1 dakikadan daha uzun bir süre boyunca herhangi bir şeye dokunmazsa, 15 dakika Oturum Kapatma zamanlayıcısını başlatırım .... Bu durumda farklılığı kontrol ederim (lastInteractionTime ve System.currentTimeMills ( )) 1 dakikadan fazla ... sonra ateş ..
Akh

3
Ancak bazı durumlarda onUserInteraction () çağrılmaz (diyaloglar onu çağırmaz ve dönenlerde kaydırma) bu durumlar için bir çözüm var mı?
AndroidNoob

MyTimerClass'ınızı paylaşabilir misiniz?
Sibelius Seraphini

20

Bence bu kodla gitmelisiniz, bu 5 dakikalık boşta oturum zaman aşımı içindir: ->

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 
}

OnUserInteraction ile hayatımı kurtardın
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 ===> mantık, sorunun kapsamı dışında olduğu için burada gösterilmemiştir

Aşağıdaki cihaz kodunu kullanarak kilidi cpu'ya uyandırabilirsiniz.

  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: O zaman lütfen bunu yapmanın doğru yolunu açıklayın. Yorumunuz belirsiz ve kararsız.
Akh

2
@AKh: Diğer cevaplar zaten olasılıkları gösteriyor. Çözümünüzde, 15 saniyede bir yoklamadan herhangi bir fayda göremiyorum. "ACTION_SCREEN_OFF" modunda 0-15 saniye arasında rastgele bir süre ile bir zamanlayıcı başlattığınızda aynı etkiye sahip olacaktır. Bu hiç mantıklı değil ..
Bez

1
@Nappy: Her 15 saniyede bir yalnızca SCREEN_ON veya SCREEN_OFF değil, aynı zamanda kullanıcının son etkileşim zamanı ve Uygulama ön plan durumunu da kontrol ediyorum. Bu üç faktöre dayanarak, kullanıcının uygulamayla ne kadar aktif etkileşim kurduğuna mantıklı bir karar veriyorum.
Akh

Lütfen yorumunuzu tamamlayınız. .... "sizin mantıksal ekranınız ise?" Ayrıca uygulamanın ön durumu da hesaba katılmalıdır.
Akh

1
Bu kod hatalarla dolu, bazı değişkenler başlatılmamış.
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));
}

Bu, çözümün temelini oluşturur, geri kalanı kısmi ihtiyaçlarınıza ve uygulama mimarisi karmaşıklığınıza bağlı olarak değiştirilebilir! Cevap için teşekkürler!
Hack06

Bu uygulama sınıfında nasıl uygulanır
Gaju Kollur

6

İşletim sistemi düzeyinde ACTION_SCREEN_OFFve ACTION_USER_PRESENTyayınların ötesinde "kullanıcı hareketsizliği" kavramı yoktur . "Hareketsizlik" i bir şekilde kendi uygulamanızda tanımlamanız gerekecektir.


6

İhtiyaçlarınızı @gfrigon veya @AKh çözümleriyle bile yönetebilirsiniz .

Ancak işte bunun için Timer ve Handlers ücretsiz çözümü . Bunun için Timer çözümünü zaten iyi yönettim. Ancak Timer ve Handler ücretsiz çözümünü başarıyla uyguladım.

Öncelikle, Zamanlayıcı veya İşleyiciler kullanıyorsanız neleri yönetmeniz gerektiğini söyleyeceğim.

  • Uygulamanız kullanıcı veya bir optimize edici tarafından öldürülürse, tüm geri aramalarınız yok edildiği için uygulamanızdan hiçbir zaman otomatik olarak çıkış yapılmaz. ( Bazı Alarm Yöneticisi veya Hizmetlerini yönetin mi? )
  • Her temel sınıfta zamanlayıcı olması iyi midir? Sadece çıkış işlemini başlatmak için birçok iş parçacığı oluşturuyorsunuz ( Statik İşleyiciyi veya Zamanlayıcıyı uygulama düzeyinde yönetin mi? ).
  • Ya kullanıcı arka plandaysa, kullanıcı uygulamanızın dışında başka bir iş yapıyorsa İşleyiciniz Giriş Etkinliğini başlatır. ( Uygulama ön planını mı arka planını mı yönetiyorsunuz? ).
  • Ya ekran otomatik olarak kapanırsa. ( Yayın alıcısında ekran kapalı yönetilsin mi? )

Sonunda bir çözüm uyguladım:

  1. NO İşleyici veya Zamanlayıcı.
  2. NO Alarm Yöneticisi.
  3. App LifeCycle'ı yönetmek DEĞİLDİR.
  4. NO ACTION_SCREEN_ON/ ACTION_SCREEN_OFFYayın Alıcısı.

En Kolay Güvenilir Çözüm

Kullanıcı etkinliğindeki son etkinlik zamanını kontrol etmek yerine, zamanlayıcılarla kullanıcının hareketsizliğini gözlemlemeyeceğiz. Bu yüzden, kullanıcı bir dahaki sefere etkileşime girdiğinde, son etkileşim zamanını kontrol ederim.

İşte BaseActivity.classbunun yerine her aktivite sınıfınızdan uzatacağınız şey LoginActivity. Çıkış sürenizi TIMEOUT_IN_MILLIbu sınıfta alana gireceksiniz .

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
Her kullanıcı etkileşiminde ana iş parçacığı üzerindeki paylaşılan tercihlere erişmek, birden çok iş parçacığını çağırmaktan daha iyidir.
Nishita

@Nishita, bu cevabı gönderirken, bu dezavantajın farkında değildim. 1 kötü cevabıma yorum yaptığınız için teşekkür ederim. Haklısın, bunu yapmanın doğru yolu bu değil. Bu cevabı saklayacağım.
Khemraj

2

Aktivite temel sınıfımda korumalı sınıf oluşturdum:

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

Yani onResume yönteminde - geri aramanızda bununla ne yapmak istediğinizi belirtebilirsiniz ...

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

kullanıcının pasif olup olmadığı nasıl kontrol edilir? sistemden herhangi bir girdi?
MohsinSyd

2

Araştırmam sırasında pek çok cevap buldum ama aldığım en iyi cevap bu. Ancak bu kodun sınırlaması, tüm uygulama için değil, yalnızca etkinlik için çalışmasıdır. Bunu referans olarak alın.

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

örneğin 8000 kullandıysanız, görev kullanıcı 8 saniye hareketsiz kaldıktan sonra yapılacaktır.


2

Kullanıcı eylemsizliği, onUserInteraction()Android'de geçersiz kılma yöntemini kullanarak algılayabilir

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

    }

Örnek kod, kullanıcı etkin olmadığında 3 dakika sonra oturumu kapatın (HomeActivity -> LoginActivity)

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

KOTLIN'de etkileşim zaman aşımındaki kullanıcıyı işleme:

     //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

İşte birkaç dakika sonra (örn. 3 dakika) kullanıcının hareketsizliğini ele alan eksiksiz bir çözüm. Bu, Uygulama zaman aşımına uğradığında arka plandayken Aktivitenin ön plana atlaması gibi genel sorunları çözer.

İlk olarak, diğer tüm Aktivitelerin genişletebileceği bir BaseActivity oluşturuyoruz.

Bu, BaseActivity kodudur.

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

    }

}

Daha sonra, "Çıkış Dinleyicimiz" için bir arayüz oluşturuyoruz

package com.example.timeout;

public interface LogoutListener {

    void onSessionLogout();

}

Son olarak, "Uygulama" yı genişleten bir Java sınıfı oluşturuyoruz.

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


}

Not: "TimeOutApp" sınıfını, manifest dosyanızın içindeki uygulama etiketinize eklemeyi unutmayın.

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

0

Sanırım zamanlayıcıyı son aktif olma zamanıyla birleştirerek olması gerekiyor.

Bunun gibi:

  1. OnCreate'de (Bundle SavedInstanceState) bir zamanlayıcı başlat, 5 dakika diyelim

  2. OnUserInteraction () içinde sadece geçerli saati saklayın

Şimdiye kadar oldukça basit.

Şimdi zamanlayıcı şunu yaptığında:

  1. Zamanı elde etmek için mevcut saati alın ve depolanan etkileşim süresini çıkarın
  2. TimeDelta> = 5 dakika ise, işleminiz tamamlanmıştır
  3. TimeDelta <5 dakika ise, zamanlayıcıyı yeniden başlatın, ancak bu sefer 5 dakikayı kullanın - kayıtlı süre. Başka bir deyişle, son etkileşim 5 dakika oluşturur

0

SO sorusuyla benzer bir durum yaşadım, 1 dakika boyunca kullanıcı hareketsizliğini takip etmem ve ardından kullanıcıyı Etkinliği başlatmak için yeniden yönlendirmem, ayrıca etkinlik yığınını da temizlemem gerekiyordu.

@Gfrigon cevabına dayanarak bu çözümü buldum.

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

Tamamlayıcı kaynaklar

Android: Etkinlik Yığını Temizle

Bu Handler sınıfı statik olmalıdır, aksi takdirde sızıntılar olabilir


0

En iyisi, bunu tüm uygulamanızda (birden fazla etkinliğiniz olduğunu varsayarak) AppLifecycleCallbacksUygulama cals'larına kaydolarak halletmektir. Sen kullanabilirsiniz registerActivityLifecycleCallbacks()(ben ActivityLifecycleCallbacks uzanan bir AppLifecycleCallbacks sınıf oluşturmayı tavsiye) Aşağıdaki geri aramaları ile Uygulama sınıfında:

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

Aktivitenizi genişletin

YourActivity:SubActivity(){}

Etkinliğinizde 3000 milisaniyeden sonra Kullanıcı etkin olmadığında MainActivity'ye ulaşmak için

Önceki bir cevabı kullandım ve kotlin'e çevirdim.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.