사용자가 내 앱을 시작하고 로그인
합니다. 세션 시간 초과를 5 분으로 선택합니다.
앱에서 일부 작업을 수행합니다. (모두 전경)
이제 사용자는 Myapp을 백그라운드로 가져오고 다른 앱을 시작합니다.
—-> 카운트 다운 타이머가 시작되고 5 분 후에
사용자가 로그 아웃하거나 사용자가 화면을 끕니다.
—-> 카운트 다운 타이머가 시작되고 5 분 후에 사용자가 로그 아웃됩니다.
앱이 포 그라운드에있을 때에도 동일한 동작을 원하지만 사용자가 6 ~ 7 분 동안 앱과 상호 작용하지 않습니다. 화면이 항상 켜져 있다고 가정합니다. 사용자 비활성 (앱이 포 그라운드에 있어도 앱과 상호 작용 하지 않음) 을 감지 하고 카운트 다운 타이머를 시작하고 싶습니다.
답변
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();
}
}
답변
비활성을 추적하는 방법은 모르지만 사용자 활동을 추적하는 방법이 있습니다. onUserInteraction()
사용자가 애플리케이션과 상호 작용할 때마다 호출되는 활동에서 호출되는 콜백을 포착 할 수 있습니다 . 다음과 같이하는 것이 좋습니다.
@Override
public void onUserInteraction(){
MyTimerClass.getInstance().resetTimer();
}
앱에 여러 활동이 포함되어있는 경우이 메서드를 추상 슈퍼 클래스 (확장 Activity
)에 넣은 다음 모든 활동이 확장하도록 하는 것은 어떻습니까 ?
답변
이 코드로 가야한다고 생각합니다. 이것은 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
}
답변
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);
}
}
답변
@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));
}
답변
OS 수준에서 “사용자 비활성”이라는 개념은 없습니다. ACTION_SCREEN_OFF
및 ACTION_USER_PRESENT
브로드 캐스트를 . 자신의 애플리케이션 내에서 어떻게 든 “비 활동”을 정의해야합니다.
답변
@gfrigon 또는 @AKh로 요구 사항을 관리 할 수도 있습니다. 솔루션으로 .
그러나 여기에 타이머 및 핸들러 무료 솔루션이 있습니다. 이 있습니다. 이미 잘 관리 된 Timer 솔루션이 있습니다. 하지만 타이머 및 핸들러 무료 솔루션을 성공적으로 구현했습니다.
먼저 Timer 또는 Handlers를 사용 하는 경우 관리 해야 할 사항 을 알려드립니다 .
- 앱이 사용자 나 옵티 마이저에 의해 종료되는 경우 모든 콜백이 삭제되므로 앱이 자동으로 로그 아웃되지 않습니다. ( 일부 알람 관리자 또는 서비스 관리? )
- 모든 기본 클래스에 타이머가있는 것이 좋은가요? 로그 아웃 프로세스를 호출하기 위해 많은 스레드를 만들고 있습니다 ( 앱 수준에서 정적 처리기 또는 타이머 관리? ).
- 사용자가 백그라운드에있는 경우 사용자가 앱 외부에서 다른 작업을 수행하는 경우 핸들러가 로그인 활동을 시작합니다. ( 앱 전경 또는 배경 관리? ).
- 화면이 자동으로 꺼지면 어떨까요? ( 브로드 캐스트 수신기에서 화면 끄기를 관리 하시겠습니까? )
마지막으로 나는 솔루션을 구현했습니다.
- 핸들러 또는 타이머가 없습니다.
- 알람 관리자가 없습니다.
- App LifeCycle을 관리하지 않습니다.
- 아니오
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.
}
}