Как вызвать метод, когда приложение Android закрыто или теряет фокус?

Поскольку приложение, которое я создаю, будет обрабатывать довольно конфиденциальные данные, я хочу синхронизировать базу данных SQLite с сервером каждый раз, когда пользователь входит в систему, и удалять emty из базы данных каждый раз, когда приложение теряет фокус (поскольку пользователь переходит на главный экран или другое приложение).

Увидев жизненный цикл Activity, я решил сделать это, очистив базу данных в onDestroy каждого действия. Чтобы протестировать описанный жизненный цикл, я просто переопределяю все методы жизненного цикла (onCreate, onStart, onResume, onPause, onStop и onDestroy), включаю в них некоторые сообщения журнала и запускаю свое приложение.

Сообщения журнала включены в мой файл SettingsActivity. Когда я вхожу в свое приложение и перехожу к настройкам, оно запускается onCreate, onStart и onResume (как и ожидалось). Когда я затем щелкаю параметр и перехожу к следующему экрану, он запускается onPause и onStop (все еще, как и ожидалось). Чтобы вернуться к экрану настроек, я нажимаю кнопку «Назад», и он снова запускается onStart и onResume (все так же, как и ожидалось), когда я теперь снова нажимаю кнопку «Назад», чтобы вернуться к начальному экрану, он (к моему удивлению) запускается onPause, onStop И onDestroy.

Итак, мои вопросы;

  1. Почему он уничтожает активность, когда приложение не завершено?
  2. И, что более важно, как запустить метод CleanUp, когда приложение закрывается или теряет фокус?

person kramer65    schedule 24.10.2013    source источник
comment
Что вы будете делать, если пользователь вытащит батарею или приложение вылетит?   -  person Eugene Mayevski 'Callback    schedule 24.10.2013
comment
@EugeneMayevski'EldoSCorp - Мы рассмотрели и такие ситуации. Очевидный ответ, конечно, ничего не хранить, а хранить все в памяти. Одна идея, которую мы придумали, заключалась в использовании базы данных SQLite в памяти, но на данный момент используемая нами форма (ActiveAndroid) не поддерживает базы данных в памяти, это было бы очень большой проблемой (но мы могли бы подумать об этом в будущем) либо перенести форму в базы данных SQLite в памяти, либо вернуться к нашим собственным подключениям к базе данных. Другая идея заключалась в том, чтобы хранить все данные в списках Java. Однако это сделало бы интеллектуальные запросы невозможными. У вас есть другая идея?   -  person kramer65    schedule 24.10.2013
comment
пришло в голову шифрование БД, но оно должно поддерживаться СУБД. Также вариантом может быть решение, отличное от СУБД, но это зависит от того, насколько тесно ваша БД связана с вашей архитектурой.   -  person Eugene Mayevski 'Callback    schedule 24.10.2013
comment
@EugeneMayevski'EldoSCorp - Но если я зашифрую базу данных, как я все равно смогу в ней искать? Кроме того, если я зашифрую базу данных, думаю, мне также нужно сохранить ключ на устройстве. Это в основном сделало бы шифрование бесполезным, верно? Или шифрование все еще будет вариантом?   -  person kramer65    schedule 24.10.2013
comment
это зависит от архитектуры вашего приложения. Здесь не может быть универсальных решений, тем более в формате комментария.   -  person Eugene Mayevski 'Callback    schedule 24.10.2013


Ответы (4)


Дополнительную информацию можно получить здесь: http://developer.android.com/training/basics/activity-lifecycle/stopping.html

Даже если я думаю, что вы уже прочитали это, потому что вы уже изучили жизненный цикл активности, вы можете видеть на первом рисунке, что onDestroy() вызывается после onStop(), и этот вызов полностью управляется системой: вы не должны ожидать какого-либо поведения. Система сама решит, КОГДА вызывать этот метод, а иногда этот метод никогда не будет вызываться (см. здесь: http://developer.android.com/reference/android/app/Activity.html). Когда системе понадобится память, ваша активность перейдет в onStop() и ничего более.

Итак, чтобы ответить на ваш второй вопрос, вы должны прочитать примечание в документации о методе onDestroy():

Примечание. Не рассчитывайте, что этот метод вызывается как место для сохранения данных! Например, если действие редактирует данные в поставщике контента, эти изменения должны быть зафиксированы либо в onPause(), либо в onSaveInstanceState. (Комплект), не здесь. Этот метод обычно реализуется для освобождения ресурсов, таких как потоки, которые связаны с активностью, чтобы уничтоженная активность не оставила таких вещей, пока остальная часть ее приложения все еще работает. Бывают ситуации, когда система просто убивает хост-процесс активности, не вызывая в нем этот метод (или любой другой), поэтому его не следует использовать для выполнения действий, которые должны оставаться после завершения процесса.

Так что совершенно ясно, что это плохое место для процесса очистки. Таким образом, вы должны использовать один из методов onPause() или onStop().

onStop() описан в документации так:

Вызывается, когда вы больше не видны пользователю. Затем вы получите onRestart(), onDestroy() или ничего, в зависимости от дальнейшей активности пользователя.

onPause() описан в документации так:

Вызывается как часть жизненного цикла действия, когда действие переходит в фоновый режим, но (еще) не было уничтожено. [...] Когда действие B запускается перед действием A, этот обратный вызов будет вызываться для A. B не будет создан до тех пор, пока не вернется onPause() A, поэтому не делайте здесь ничего длинного.< /strong> [...] В ситуациях, когда системе требуется больше памяти, она может остановить приостановленные процессы, чтобы восстановить ресурсы.

Теперь мы знаем, что onPause() предназначен для сохранения ваших данных, а также что после выполнения onPause() система может завершить ваш процесс. Таким образом, выполнение очистки в onPause() кажется самым безопасным местом, поскольку вы почти уверены, что оно будет вызываться каждый раз.

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

Чтобы возобновить: сделайте процесс очистки в методе onPause() и процесс инициализации в методе onResume(). Имейте в виду, что ваше приложение может работать очень медленно при таком процессе.

Надеюсь, это поможет вам.

person mithrop    schedule 24.10.2013
comment
Спасибо за развернутый ответ. Я все еще задаюсь вопросом, хотя; как мне проверить onPause, переключается ли пользователь на другой вид или приложение фактически закрывается (пользователем, нажимающим кнопку «Домой», или системой, требующей ресурсов)? Фрагмент кода был бы очень признателен .. :) - person kramer65; 24.10.2013
comment
Здесь вы находитесь не на уровне приложений, а на уровне действий. Вы не управляете всем жизненным циклом приложения, а только представлениями. Так что, возможно, вы никогда не сможете узнать, что будет дальше. Но с пользовательской реализацией метода View.onKeyDown() (developer.android .com/reference/android/view/, android.view.KeyEvent)), уверен, у вас получится сделать то, что вы хотите :) - person mithrop; 24.10.2013
comment
Если ответ помог вам, не забудьте принять его для других читателей из Google :) - person mithrop; 25.10.2013
comment
onStop() так описывается в документации, кажется, это устаревшая цитата? это уже нигде не описано - person Captain Obvious; 14.04.2017

Уничтожение активности сзади — это нормальное поведение. С сайта для разработчиков Android.

Есть несколько сценариев, в которых ваша активность уничтожается из-за нормального поведения приложения, например, когда пользователь нажимает кнопку "Назад"...

Имеет для обнаружения, когда приложение переходит в фоновый режим, нет простого вызова метода, который сообщит вам об этом. Однако этот предыдущий вопрос содержит несколько хороших ответов о том, как это сделать.

person Francis    schedule 24.10.2013

Вы не можете сделать это (вызвать функцию) в java-части приложения. Только в родной части.

person theWalker    schedule 24.10.2013
comment
Как вы имеете в виду? Я могу просто написать простой класс, импортировать его и запустить в нем метод в любой части приложения, верно? - person kramer65; 24.10.2013

Что касается вашего второго вопроса, таким образом вы можете запустить свой метод CleanUp, когда приложение полностью закроется. Вам нужно будет реализовать свой метод внутри службы, которую в данном случае я назвал «ExitService».

Сначала создайте этот класс обслуживания:

 public class ExitService extends Service {


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onTaskRemoved(Intent rootIntent) {
        System.out.println("onTaskRemoved called");
        super.onTaskRemoved(rootIntent);
        //do something you want before app closes.

ADD YOUR METHOD HERE, or CALL IT

        //stop service
        this.stopSelf();
    }
}

Затем объявите таким образом свою службу в метке манифеста «приложение»:

<service
            android:enabled="true"
            android:name=".ExitService"
            android:exported="false"
            android:stopWithTask="false" />

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

 Intent intent = new Intent(this, ExitService.class);
        startService(intent);
person danielrosero    schedule 19.03.2018
comment
Этот метод службы onTaskRemoved() вызывается, когда система Android принудительно останавливает приложение, когда оно сталкивается с нехваткой памяти? - person Dharma Sai Seerapu; 25.03.2019