onPause() и onStop() в Activity

Я новичок в разработке Android и до сих пор не могу понять методы onPause() и onStop() в действии.

В моем приложении у меня есть статический класс, который я называю Counter, и он сохраняет состояние переменных в памяти для приложения. Мое приложение отлично работает в эмуляторе. То, что я пытался проверить, было дифференциальным поведением onPause() по сравнению с onStop().

Для onPause я хотел, чтобы значения, хранящиеся в членах класса Counter, сохранялись, тогда как при вызове onStop() я хотел, чтобы значения счетчика были сброшены на ноль. Поэтому я переопределяю onStop() и устанавливаю переменные внутри класса счетчика равными нулю. Однако в эмуляторе я не могу получить приложение в состоянии паузы. В эмуляторе я открываю свое приложение, тренирую его. Затем я нажимаю кнопку «Домой» (не кнопку «Назад») эмулятора и запускаю другое приложение, полагая, что это будет имитировать действие onPause(). Однако эмулятор, похоже, не соблюдает это (я использую эмулятор armeabi v7a), он, кажется, всегда вызывает onStop(), потому что все значения моего счетчика возвращаются к нулю в соответствии с моим переопределением в onStop(). Это присуще эмулятору или я делаю что-то не так, чтобы поставить свою активность в состояние паузы?


person Stephan Doliov    schedule 08.07.2012    source источник
comment
Можете ли вы включить код, чтобы подчеркнуть вашу проблему?   -  person t0mm13b    schedule 09.07.2012
comment
См. [При каких обстоятельствах появление диалогового окна вызовет вызов onPause()?] [1] [1]: stackoverflow.com/questions/7240916/   -  person Yuvraj Kakkar    schedule 07.06.2014


Ответы (6)


Я не уверен, с каким эмулятором вы тестируете, но onPause — это метод, который всегда гарантированно вызывается, когда ваш Activity теряет фокус (и я говорю всегда, потому что на некоторых устройствах, особенно на Android 3.2+, onStop не всегда гарантированно вызывается до того, как Activity будет уничтожен).

Хороший способ понять жизненный цикл Activity для начинающих — засорить переопределенные методы Log. Например:

public class SampleActivity extends Activity {

    /**
     * A string constant to use in calls to the "log" methods. Its
     * value is often given by the name of the class, as this will 
     * allow you to easily determine where log methods are coming
     * from when you analyze your logcat output.
     */
    private static final String TAG = "SampleActivity";

    /**
     * Toggle this boolean constant's value to turn on/off logging
     * within the class. 
     */
    private static final boolean VERBOSE = true;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (VERBOSE) Log.v(TAG, "+++ ON CREATE +++");
    }

    @Override
    public void onStart() {
        super.onStart();
        if (VERBOSE) Log.v(TAG, "++ ON START ++");
    }

   @Override
    public void onResume() {
        super.onResume();
        if (VERBOSE) Log.v(TAG, "+ ON RESUME +");
    }

    @Override
    public void onPause() {
        super.onPause();
        if (VERBOSE) Log.v(TAG, "- ON PAUSE -");
    }

    @Override
    public void onStop() {
        super.onStop();
        if (VERBOSE) Log.v(TAG, "-- ON STOP --");
    }

   @Override
    public void onDestroy() {
        super.onDestroy();
        if (VERBOSE) Log.v(TAG, "- ON DESTROY -");
    }
}
person Alex Lockwood    schedule 08.07.2012
comment
Спасибо, Алекс, у меня уже есть разметка журнала, я должен был упомянуть об этом. Журналы показывают мне, что onPause() действительно вызывается. Проблема для меня в эмуляторе в том, что я хочу, чтобы onStop() не вызывался. Поэтому, когда я нажимаю кнопку «Домой», мои журналы показывают, что onPause() действительно вызывается, как и ожидалось. Однако, когда я переключаю приложения в эмуляторе (например, из моего приложения в веб-браузер), мои журналы также показывают мне, что вызывается onStop() для моего приложения. Я ожидаю, что onStop() будет вызываться только в том случае, если системе не хватает ресурсов, и, возможно, виртуальной машине? - person Stephan Doliov; 09.07.2012
comment
Хм ... вы возились с настройками разработчика? Настройки --› Настройки разработчика --› уничтожить все действия, возможно, стоит галочка? Помимо этого, важно понимать, что никогда не гарантируется, что onStop будет вызван... как показано здесь: bit.ly/OMB0as - person Alex Lockwood; 09.07.2012
comment
@StephanDoliov Я упомянул проверку настроек разработчиков, потому что кажется странным, что onStop НИКОГДА не вызывается. Я не уверен, почему это происходит. Держу пари, что если вы протестируете на реальном устройстве, вы не получите такого же поведения. Что происходит, когда вы нажимаете кнопку домой? Это один из популярных способов обращения к onStop. - person Alex Lockwood; 09.07.2012
comment
Важно отметить, что onStop() теперь гарантированно вызывается для пост-сотовых устройств. См.: stackoverflow.com/q/29395169/3960852 - person Kenny Worden; 19.07.2017
comment
Сейчас 2018 год. Но документация показывает, что onStop() можно убить для всех версий, и показывает, что onPause() можно убить в пре-сотах - i.imgur.com/CYpQdSL.png (разработчик .android.com/reference/android/app/Activity.html) - person Cheok Yan Cheng; 08.02.2018
comment
Спасибо, я лечил ошибку несколько дней, не зная, что происходит, эти журналы спасают меня! - person Daniel Beltrami; 05.12.2018

Я знаю, что ваш вопрос был 6 месяцев назад, но на случай, если кто-то еще наткнется на этот вопрос:

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

Да, вы. Этот:

Я нажимаю кнопку «Домой» (не кнопку «Назад») эмулятора и запускаю другое приложение, полагая, что это будет имитировать действие onPause().

Нажатие кнопки «Домой» действительно вызовет метод onPause(), но поскольку кнопка «Домой» делает вашу активность более невидимой, она вызовет метод onStop() (например, упомянутый патриот и милтер).

Согласно справочнику разработчиков по действиям (http://developer.android.com/guide/components/activities.html) вы можете отобразить диалоговое окно или просто перевести устройство в спящий режим.

В качестве альтернативы вы вызываете действие, которое лишь частично будет препятствовать вызывающему действию. Итак, вызовите активность, которая создает окно с представлением размера:

 android:layout_width="100dp"
 android:layout_height="100dp"

Который не покрывает весь экран, поэтому вызывающая активность остается частично видимой, вызывая только метод onPause() вызывающей активности.

Клонируйте это действие так, чтобы оба размера представления были «match_parent» вместо «100dp», и вызовите его, и оба метода onPause() и onStop() вызывающего действия будут вызваны, потому что вызывающее действие не будет видно.

Конечно, могут быть исключения, например, если вызываемая активность вызывает сбой приложения в любом из своих onCreate(), onStart() или onResume(), тогда onStop() вызывающей активности не будет вызываться, очевидно, я просто говорю здесь об общем случае.

person Julien Rousseau    schedule 03.04.2013

Различия между вызовами onPause() и onStop() могут быть довольно тонкими. Однако, как объясняется здесь, onPause() обычно выполняется когда другое действие получает фокус (возможно, в виде всплывающего окна или прозрачного окна), в то время как текущее действие все еще выполняется. Если вы полностью выйдете из приложения (например, нажав кнопку «Домой»), активность больше не будет видна, и система может выполнить onStop(). Я говорю «может» только потому, что, как упомянул Алекс, в некоторых случаях onStop не вызывается до того, как действие будет уничтожено.

person patriot    schedule 08.07.2012
comment
как я могу гарантировать, что onStop() будет вызываться после того, как я нажму кнопку «Назад» или завершу вызов? - person Amit; 20.12.2012

при паузе():

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

приостановке():

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

Взято из класса эталонной активности Android: http://developer.android.com/reference/android/app/Activity.html

person nik    schedule 08.07.2012

Если вы эмулируете Android 4.x, вы можете контролировать, как система обрабатывает фоновые действия, используя «Настройки» -> «Параметры разработчика» -> «Не сохранять действия» и «Ограничение фонового процесса». Для более старых версий есть приложение Dev Tools, которое содержит те же настройки. Однако в условиях нехватки памяти система может проигнорировать эти настройки и закрыть ваше приложение. Может помочь увеличение объема памяти, выделенной эмулятору.

Кроме того, если вы повторно запускаете свое приложение из Eclipse, оно убьет предыдущий процесс, а не завершит его корректно.

person Tamás Szincsák    schedule 08.07.2012

Согласен с milter!

при паузе():

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

Если вы переключаете приложения, не нажимая Назад (нажмите и удерживайте ДОМОЙ), то ОС вызовет onPause. Когда вы вернетесь к своей деятельности (снова нажмите и удерживайте HOME) в onResume, у вас должны быть сохранены все ваши личные переменные. Но вы же не можете контролировать пользователя, верно?!

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

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

@Override 
public void onSaveInstanceState(Bundle savedInstanceState) { 
  super.onSaveInstanceState(savedInstanceState); 
  // Save UI state changes to the savedInstanceState. 
  // This bundle will be passed to onCreate if the process is 
  // killed and restarted. 

  savedInstanceState.putLong("elapsedTime", elapsedTime);
  // etc. 
} 

И мой код для восстановления:

@Override 
public void onRestoreInstanceState(Bundle savedInstanceState) { 
  super.onRestoreInstanceState(savedInstanceState); 
  // Restore UI state from the savedInstanceState. 
  // This bundle has also been passed to onCreate. 

  elapsedTime = savedInstanceState.getLong("elapsedTime");
} 

Поместите эти методы внутри своего класса, и все готово. Имейте в виду, что строка "elapsedTime" в моем случае является КЛЮЧОМ к системе и должна быть уникальной. Используйте уникальные строки для каждой части данных, которые вы хотите сохранить. Например, «startClock», «ClockTextColor» и т. д.

person Gilson    schedule 09.06.2013