Android에서 사용자 비활성을 감지하는 방법


101

사용자가 내 앱을 시작하고 로그인
합니다. 세션 시간 초과를 5 분으로 선택합니다.
앱에서 일부 작업을 수행합니다. (모두 전경)
이제 사용자는 Myapp을 백그라운드로 가져오고 다른 앱을 시작합니다.
----> 카운트 다운 타이머가 시작되고 5 분 후에
사용자가 로그 아웃하거나 사용자가 화면을 끕니다.
----> 카운트 다운 타이머가 시작되고 5 분 후에 사용자가 로그 아웃됩니다.

앱이 포 그라운드에있을 때에도 동일한 동작을 원하지만 사용자가 6 ~ 7 분 동안 앱과 상호 작용하지 않습니다. 화면이 항상 켜져 있다고 가정합니다. 사용자 비활성 (앱이 포 그라운드에 있어도 앱과 상호 작용 하지 않음) 을 감지 하고 카운트 다운 타이머를 시작하고 싶습니다.


1
항상 타이머를 실행하고 사용자가 무언가를 할 때마다 재설정 할 수 있습니까?
Kyle P

답변:


111

Fredrik Wallenius의 답변을 기반으로 매우 간단하다고 생각되는 솔루션을 찾았습니다. 이것은 모든 활동에 의해 확장되어야하는 기본 활동 클래스입니다.

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
이렇게하면 생성 된 각각에 대해 Handler및 의 여러 인스턴스가 생성됩니다. 이 두 멤버를으로 변환하면 이를 방지 할 수 있습니다. 또한, 당신은 당신이 전화 한 이유를 말해 줄 수 에서 `?RunnableActivitystaticstopDisconnectTimer()onStop()
Gaurav Bhor

@Gaurav 제 경우에는 하나의 활동에서만 구현됩니다 (따라서 static수정 자로 문제를 파악하지 못했습니다 ). 에 관해서는 onStop(), 내가 기억하는 것에서 나는 onBackPressed()연결 해제 콜백에서 로그인 화면으로 돌아 가기 위해 호출하고 차례로 onStop()메서드를 호출합니다 . 로그인 화면에 사용자의 반환을 수동으로 다시 눌러 타이머 요구에 잘 따라서으로 정지 할 때 stopDisconnectTimer()에서 onStop(). 이 부분은 귀하의 요구와 구현에 달려 있다고 생각합니다.
gfrigon 2014-08-27

@gfrigon 사용자를 로그인 활동으로 리디렉션 할 수 있습니까?
Apostrofix

@Apostrifix, 물론 가능합니다. 제 경우에는 단 하나의 활동이있었습니다 onBackPressed(). 스택에 둘 이상의 활동이있는 경우 해당 문제에 대한 인 텐트를 생성하기 만하면됩니다. 활동 작업을 지우고 사용자가 다시 연결하지 못하도록하기 위해 다음 답변을 살펴볼 수 있습니다. stackoverflow.com/questions/7075349/…
gfrigon

훌륭한 일! runnable에 대해 getter와 setter를 추가 한 다음 필요에 따라 onCreate 메서드를 사용하여 확장 클래스에 설정했습니다 ... 완벽합니다. 다시 한 번 감사드립니다.
CrandellWS

90

비활성을 추적하는 방법은 모르지만 사용자 활동을 추적하는 방법이 있습니다. onUserInteraction()사용자가 애플리케이션과 상호 작용할 때마다 호출되는 활동에서 호출되는 콜백을 포착 할 수 있습니다 . 다음과 같이하는 것이 좋습니다.

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

앱에 여러 활동이 포함되어있는 경우이 메서드를 추상 슈퍼 클래스 (확장 Activity)에 넣은 다음 모든 활동이 확장하도록 하는 것은 어떻습니까 ?


1
예, 이것은 한 가지 방법입니다 ...하지만 내 앱에는 30 개의 서로 다른 활동이 있으며 사용자가 활성 상태 일 때 상호 작용이 너무 많을 것입니다. 따라서 타이머를 재설정 할 때마다 비용이 많이 드는 작업이됩니다. 최악의 경우는 1 분에 50 ~ 60 회 정도 될 수 있습니다.
Akh

3
시간을 정하지는 않았지만 다음과 같이 타이머를 재설정한다고 말하고 싶습니다. lastInteraction = System.currentTimeMillis (); 예를 들어 2ms가 걸립니다. 1 분에 60 번하면 120ms를 "느슨하게"합니다. 60000 중에서.
Fredrik Wallenius

1
Fredrik ...이 시나리오를 충족하기 위해 귀하의 제안도 사용하고 있습니다. 화면 시간 제한은 기기에서 최대 30 분으로 설정되어 있습니다. MyApp shd timeout after 15 mins ... 사용자가 1 분 이상 화면에서 아무것도 터치하지 않으면 15 분 Logout 타이머를 시작합니다 ....이 경우에는 differentenct (lastInteractionTime 및 System.currentTimeMills ()를 확인합니다. )) 1 분 이상 ... 발사 ..
Akh

3
onUserInteraction ()은 일부 인스턴스에서 호출되지 않지만 (대화 상자에서 호출하지 않고 스피너에서 스크롤) 이러한 상황에 대한 해결 방법이 있습니까?
AndroidNoob 2014

MyTimerClass를 공유 할 수 있습니까?
Sibelius Seraphini

19

이 코드로 가야한다고 생각합니다. 이것은 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 
}

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 ===> 논리는 질문의 범위를 벗어나므로 여기에 표시되지 않습니다.

아래 장치 코드를 사용하여 CPU 잠금을 해제 할 수 있습니다.

  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 : 그럼 올바른 방법을 설명해주세요. 귀하의 의견은 모호하고 우유부단합니다.
Akh

2
@AKh : 다른 답변은 이미 가능성을 보여줍니다. 귀하의 솔루션에서는 15 초마다 폴링의 이점을 볼 수 없습니다. 0-15 초의 임의 기간으로 "ACTION_SCREEN_OFF"에서 타이머를 시작하는 것과 동일한 효과가 있습니다. 이건
말도

1
@Nappy : 15 초마다 SCREEN_ON 또는 SCREEN_OFF뿐만 아니라 사용자의 마지막 상호 작용 시간과 앱 전경 상태도 확인합니다. 이 세 가지 요소를 기반으로 사용자가 앱과 상호 작용하는 정도에 대한 논리적 결정을 내립니다.
Akh

댓글을 작성해주세요. .... "isScreenof 부울이?" 또한 앱 이전 상태도 고려해야합니다.
Akh

1
이 코드는 실수로 가득 차 있으며 일부 변수는 초기화되지 않습니다.
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));
}

이것이 솔루션의 기본이며 나머지는 일부 요구 사항과 애플리케이션 아키텍처 복잡성에 따라 수정할 수 있습니다! 답변 해주셔서 감사합니다!
Hack06

응용 클래스에 적용하는 방법
Gaju Kollur

6

OS 수준에서 "사용자 비활성"이라는 개념은 없습니다. ACTION_SCREEN_OFFACTION_USER_PRESENT브로드 캐스트를 . 자신의 애플리케이션 내에서 어떻게 든 "비 활동"을 정의해야합니다.


6

@gfrigon 또는 @AKh로 요구 사항을 관리 할 수도 있습니다. 솔루션으로 .

그러나 여기에 타이머 및 핸들러 무료 솔루션이 있습니다. 이 있습니다. 이미 잘 관리 된 Timer 솔루션이 있습니다. 하지만 타이머 및 핸들러 무료 솔루션을 성공적으로 구현했습니다.

먼저 Timer 또는 Handlers를 사용 하는 경우 관리 해야 할 사항 알려드립니다 .

  • 앱이 사용자 나 옵티 마이저에 의해 종료되는 경우 모든 콜백이 삭제되므로 앱이 자동으로 로그 아웃되지 않습니다. ( 일부 알람 관리자 또는 서비스 관리? )
  • 모든 기본 클래스에 타이머가있는 것이 좋은가요? 로그 아웃 프로세스를 호출하기 위해 많은 스레드를 만들고 있습니다 ( 앱 수준에서 정적 처리기 또는 타이머 관리? ).
  • 사용자가 백그라운드에있는 경우 사용자가 앱 외부에서 다른 작업을 수행하는 경우 핸들러가 로그인 활동을 시작합니다. ( 앱 전경 또는 배경 관리? ).
  • 화면이 자동으로 꺼지면 어떨까요? ( 브로드 캐스트 수신기에서 화면 끄기를 관리 하시겠습니까? )

마지막으로 나는 솔루션을 구현했습니다.

  1. 핸들러 또는 타이머가 없습니다.
  2. 알람 관리자가 없습니다.
  3. App LifeCycle을 관리하지 않습니다.
  4. 아니오 ACTION_SCREEN_ON/ ACTION_SCREEN_OFF방송 수신기.

가장 쉽고 신뢰할 수있는 솔루션

사용자 활동에 대한 마지막 활동 시간을 확인하는 대신 타이머로 사용자 활동이없는 것을 관찰하지 않습니다. 그래서 사용자가 다음에 앱을 상호 작용할 때 마지막 상호 작용 시간을 확인합니다.

다음은 BaseActivity.class당신이 대신 활동 클래스의 모든에서 확장하는 것이다 LoginActivity. TIMEOUT_IN_MILLI이 클래스의 필드 에서 로그 아웃 시간을 정의합니다 .

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

여러 스레드를 호출하는 것보다 모든 사용자 상호 작용에서 기본 스레드의 공유 기본 설정에 액세스하는 것이 더 낫습니다.
Nishita

이 답변을 게시 할 때 @Nishita는이 불만을 인식하지 못했습니다. 내 1 개의 잘못된 답변에 대해 의견을 보내 주셔서 감사합니다. 당신이 옳습니다, 이것은 그것을하는 올바른 방법이 아닙니다. 나는이 대답을 숨길 것이다.
Khemraj

2

내 활동 기본 클래스에서 보호 된 클래스를 만들었습니다.

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

사용자가 비활성 상태인지 확인하는 방법 ?? 시스템의 입력?
MohsinSyd

2

검색하는 동안 많은 답변을 찾았지만 이것이 제가받은 최고의 답변입니다. 그러나이 코드의 한계는 전체 애플리케이션이 아닌 활동에 대해서만 작동한다는 것입니다. 이것을 참고로 삼으십시오.

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 초 동안 사용자 활동이 없으면 작업이 완료됩니다.


2

사용자 비활성은 onUserInteraction()Android에서 재정의 방법을 사용하여 감지 할 수 있습니다.

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

    }

다음은 사용자가 비활성 상태 일 때 3 분 후 로그 아웃 (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에서 상호 작용 시간 초과시 사용자 처리 :

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

다음은 몇 분 (예 : 3 분) 후 사용자 비활성을 처리하는 완벽한 솔루션입니다. 이렇게하면 시간 초과시 앱이 백그라운드에있을 때 활동이 포 그라운드로 점프하는 것과 같은 일반적인 문제가 해결됩니다.

첫째, 다른 모든 활동이 확장 할 수있는 BaseActivity를 만듭니다.

이것은 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();

}

마지막으로 "Application"을 확장하는 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>

0

타이머와 마지막 활동 시간을 결합해야한다고 생각합니다.

그래서 이렇게 :

  1. onCreate (Bundle savedInstanceState)에서 타이머를 시작합니다 (예 : 5 분).

  2. onUserInteraction ()에서는 현재 시간 만 저장합니다.

지금까지는 매우 간단합니다.

이제 타이머 팝이 다음과 같이 할 때 :

  1. 현재 시간에서 저장된 상호 작용 시간을 빼서 timeDelta를 얻습니다.
  2. timeDelta가 5 분 이상이면 완료된 것입니다.
  3. timeDelta가 5 분 미만이면 타이머를 다시 시작하지만 이번에는 저장된 시간 인 5 분을 사용합니다. 즉, 마지막 상호 작용에서 5 분

0

나는 1 분 동안 사용자 비활성을 추적 한 다음 사용자를 활동을 시작하도록 리디렉션해야하는 SO 질문과 비슷한 상황을 가졌고 활동 스택도 정리해야했습니다.

@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 : 활동 스택 지우기

이 핸들러 클래스는 정적이어야합니다. 그렇지 않으면 누수가 발생할 수 있습니다.


0

가장 좋은 점은 AppLifecycleCallbacksApplication calss 에 등록하여 전체 앱에서이 문제를 처리하는 것입니다 (여러 활동이 있다고 가정) . registerActivityLifecycleCallbacks()다음 콜백과 함께 Application 클래스에서 사용할 수 있습니다 (ActivityLifecycleCallbacks를 확장하는 AppLifecycleCallbacks 클래스를 만드는 것이 좋습니다).

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

활동 확장

YourActivity:SubActivity(){}

YourActivity에서 3000 밀리 초 후에 사용자가 비활성 상태 일 때 MainActivity로 이동하는 방법

이전 답변을 사용하여 kotlin으로 변환했습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.