Android에서 사용자 비활성을 감지하는 방법 전경) 이제 사용자는 Myapp을

사용자가 내 앱을 시작하고 로그인
합니다. 세션 시간 초과를 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_OFFACTION_USER_PRESENT브로드 캐스트를 . 자신의 애플리케이션 내에서 어떻게 든 “비 활동”을 정의해야합니다.


답변

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