Как обнаружить неактивность пользователя на какое-то время при множественной активности на андроиде - PullRequest
0 голосов
/ 29 мая 2018

Я знаю, что тот же вопрос здесь , уже заданный кем-то, и на него есть ответ, но у меня есть проблема с этим ответом.

Мое требование - я хочу определитьесли пользователь неактивен в течение 5 минут, то пользователь получает автоматический выход из приложения и загружает вход и выход из системы на сервере.

Я перепробовал все ответы по приведенной выше ссылке, но этот ответ работаетдля одного действия, но я хочу отслеживать его для нескольких действий.

Для этого я создал абстрактный класс

public abstract class SessionTimeOutActivity extends BaseActivity {

    public static final long DISCONNECT_TIMEOUT = 1000 * 60; // 5 min = 5 * 60 * 1000 ms

    private static Handler disconnectHandler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            Log.d("SessionTimeOutActivity", "disconnectHandler");

            return false;
        }
    });

    private Runnable disconnectCallback = new Runnable() {
        @Override
        public void run() {
            // Perform any required operation on disconnect
            Log.d("SessionTimeOutActivity", "disconnectCallback");


            Toast.makeText(getApplicationContext(), "Session time out", Toast.LENGTH_LONG).show();
            Intent intent = new Intent(getApplicationContext(), LoginActivity.class);
            startActivity(intent);
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);

            finish();

        }
    };

    public void resetDisconnectTimer() {
        disconnectHandler.removeCallbacks(disconnectCallback);
        disconnectHandler.postDelayed(disconnectCallback, DISCONNECT_TIMEOUT);
    }

    public void stopDisconnectTimer() {
        disconnectHandler.removeCallbacks(disconnectCallback);
    }

    @Override
    public void onUserInteraction() {
        Log.d("SessionTimeOutActivity", "onUserInteraction");
        resetDisconnectTimer();
    }

    @Override
    public void onResume() {
        super.onResume();
//        resetDisconnectTimer();
    }

    @Override
    public void onStop() {
        super.onStop();
//        stopDisconnectTimer();
    }


}

Другие действия в приложении

    public class MenuActivtyNav extends SessionTimeOutActivity{
.....
}

MenuActivity

 public class MenuActivty extends SessionTimeOutActivity{
....
}

Проблема

1) На экране блокировки автоматический выход из системы не работает, не вызывается disconnectCallback

2) Во время использованияприложение показывает тост сообщение "Время ожидания сеанса"

Ответы [ 2 ]

0 голосов
/ 03 июня 2018

Даже вы можете справиться со своими требованиями, приложив этот ответ .

Но я думал о некоторых бесплатных решениях для таймеров и обработчиков для этого.У меня уже есть хорошо управляемое решение для этого.Но я успешно внедрил бесплатное решение для таймеров и обработчиков.

Сначала я расскажу , что вам нужно сделать , если вы используете таймер или обработчики.

  • Если вашприложение удаляется пользователем или оптимизатором, ваше приложение никогда не выйдет из системы автоматически, потому что все ваши обратные вызовы уничтожены.( Управление каким-либо Alarm Manager или службой? )
  • Хорошо ли иметь таймер в каждом базовом классе?Вы создаете много потоков только для вызова процесса выхода из системы ( Управление статическим обработчиком или таймером на уровне приложения? ).
  • Что, если пользователь находится в фоновом режиме, ваш обработчик запустит активность входа, если пользовательделать какую-то другую работу за пределами вашего приложения.( Управление передним планом или фоном приложения? ).
  • Что делать, если экран автоматически отключается.( Управление выключением экрана на приемнике вещания? )

Наконец-то я реализовал решение, которое

  1. Вам не нужно использовать Hander или Timer.
  2. Вам не нужно использовать Alarm Manager.
  3. Вам не нужно использовать App Lifecycle.
  4. Вам не нужно использовать ACTION_SCREEN_ON /ACTION_SCREEN_OFF Приемник вещания.

Решение

Мы не будем наблюдать за неактивностью пользователя таймерами, а не будем проверять время последней активности пользователя.Поэтому, когда пользователь в следующий раз взаимодействует с приложением, я проверяю время последнего взаимодействия.

Вот BaseActivity.class, которое вы будете расширять для каждого класса активности вместо LoginActivity.

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.
    }
}
0 голосов
/ 31 мая 2018

Давайте начнем с понимания причин, по которым ваш код не выполняет то, что вы хотите.

Проблема 1. Вам следует избегать длительных задач в ваших действиях на Android, особенно когда онине видны, потому что система может уничтожить вашу деятельность или процесс приложения, поэтому код не будет запущен.

Проблема 2. Каждое действие отправляет обратный вызов disconnect вашему обработчику, ив случае, когда пользователь взаимодействует со вторым действием, обратный вызов первого действия не будет сброшен и сработает.

Решение.

Теперь давайте подумаем о подходе к решениюэтот.Было бы лучше иметь одно место для отслеживания бездействия.Это может быть одиночка или вы можете использовать объект приложения.И обрабатывать 2 случая отдельно: первый - если ваш пользователь находится внутри приложения и не использует его, а другой - когда ваш пользователь выходит из приложения.

Для первой цели у вас может быть подход, аналогичныйваш текущий, но сделайте общий доступ disconnectCallback в приложении.Переместите обработчик, функцию обратного вызова и сбросьте логику обратного вызова в свой класс приложения и сделайте

@Override
public void onUserInteraction()

вызов resetCallback в приложении.Это заставит все Действия использовать один и тот же обратный вызов и решить проблему 2.

Для второй цели вы можете использовать Обратные вызовы жизненного цикла действия .Каждый раз, когда ваша деятельность приостанавливается, сохраняйте отметку времени.Затем при каждом возобновлении активности сравнивайте эту временную метку со временем возобновления, если оно больше 5 минут, затем выйдите из системы и перейдите к экрану входа.Это решит проблему 1. Вам нужно будет сохранить эту временную метку, потому что приложение может быть убито системой, а все разделяемое в памяти будет удалено.Например, используйте общие настройки.

И последнее, вам нужно отменить обратные вызовы, когда приложение переходит в фоновый режим.Вы можете сделать это в onActivityPaused(Activity activity) ваших обратных вызовов активности, там же, где вы будете запускать логику для второго случая.

...