Когда регистрировать / отменять регистрацию получателей трансляций, созданных в процессе?

79

Мне нужно создать настраиваемый широковещательный приемник в событии onCreate действия, и, очевидно, мне нужно отменить регистрацию широковещательного приемника в событии onDestroy действия

Для наглядности это фрагмент кода, который я использую.

public class AnActivity extends Activity {
    private ResponseReceiver receiver;

    public class ResponseReceiver extends BroadcastReceiver {
           public static final String ACTION_RESP =
              "mypackagename.intent.action.MESSAGE_PROCESSED";

           @Override
            public void onReceive(Context context, Intent intent) {
// TODO Start a dialogue if message indicates successfully posted to server
            }
    }   

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        IntentFilter filter = new IntentFilter(ResponseReceiver.ACTION_RESP);
        filter.addCategory(Intent.CATEGORY_DEFAULT);
        receiver = new ResponseReceiver();
        registerReceiver(receiver, filter);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterReceiver(receiver);
    }

Я читал, что события onPause / onResume и onStart / onStop для действия также должны регистрировать и отменять регистрацию широковещательного приемника.

Я действительно хочу понять, что для этого считается лучшим и почему.

Jamesc
источник
Это потому, что при onDestroy()вызове события больше не будут прослушиваться получателем.
de_billa_

Ответы:

91

Вы должны зарегистрировать и отменить регистрацию ваших получателей onStart()и onStop().

Единственная причина, по которой Activity будет регистрировать BroadcastReceivers, - это каким-то образом использовать события в текущем действии, чтобы информировать пользователя о событии. Если onStop()был вызван, то Activityон больше не находится на переднем плане и, следовательно, не может обновить пользователя.

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

Как говорит Константин, звонок onDestroy()не гарантируется, и вы можете продолжать получать трансляции в течение долгого времени, когда Activityперестанет работать.

SnowyTracks
источник
3
Вы предлагаете мне зарегистрироваться в onResume ВМЕСТО из onCreate или как? Всегда ли вызывается onResume при создании действия?
jamesc
9
Вы должны зарегистрироваться onResume, да, onResume () всегда вызывается для отображаемой активности (это последний метод, вызываемый перед появлением вашей активности ( developer.android.com/reference/android/app/Activity.html ), если вы регистрируетесь только в onCreate () и отмените регистрацию onPause (), то в следующий раз, когда действие будет выведено на передний план, onCreate () не будет вызываться снова, и тогда он не будет регистрировать получателя снова. И да, я имею в виду INSTEAD of, не делайте этого onCreate ().
SnowyTracks
1
@SnowyTracks: не могли бы вы прокомментировать, почему предпочтительнее выполнять вызовы регистрации BroadcastReceiver в onResume / onPause, а не в onStart / onStop? Просматривая руководство разработчика для связанных служб, я нашел это . В конце этого раздела рекомендуется выполнять привязку / отмену привязки службы в onStart / onStop, а не в onResume / onPause (по соображениям производительности). Интересно, относится ли это также к BroadcastReceivers? Заранее спасибо.
Янус Вармаркен
1
@jvmk Согласен, в Android-документе говорится, что это нужно делать в onStart и onStop, я думаю, что в 99% случаев это не имеет большого значения, разница только в поведении - это диалоговые действия или используются частичные действия переднего плана. Но я обновлю свой ответ, чтобы он соответствовал документу Android.
обновлю
1
Я вижу, вы вчера редактировали второй абзац ... спасибо, что постарались дать более последовательный ответ. Но это все еще не объясняет, почему следует использовать onStart / onStop вместо или в сочетании с onResume / onPause , что было вопросом OP. Вместо этого объяснение во втором абзаце одинаково верно как для onResume / onPause, так и для onStart / onStop: после вызова onPause активность больше не находится на переднем плане. Итак, мы остались без ответа на вопрос "почему" для вашей рекомендации.
LarsH
19

Поскольку onDestroy()звонок не гарантируется, вы должны использовать его onPause()для отмены регистрации. Рассмотрите жизненный цикл вашего широковещательного приемника: нужно ли вам, чтобы он был активен только тогда, когда ваша деятельность находится на переднем плане? Затем используйте onResume()/onPause()

Константин Приблуда
источник
что, если нам все еще нужно обновить содержимое в действии, даже если действие находится в фоновом режиме, потому что пользователь может возобновить приложение, и в этом случае должны отображаться обновленные данные?
Усман Рана
9

В документации Android не прописано единое место для регистрации / отмены регистрации широковещательных приемников, но упоминаются как onStart()/, так onStop()иonResume() / onPause()как возможности.

Самый важный фактор при принятии этого решения - когда ваш ресивер должен выполнять свою работу? Это определит, когда регистрировать и отменить регистрацию.

  • Должен ли получатель что-то делать с трансляцией только тогда, когда активность находится в фокусе? В таком случае вы можете зарегистрировать / отменить регистрацию в onPause()/ onReceive(). (Вы также можете использовать более длительный срок службы, например onStart()/ onStop(), но тогда вы должны проверить во время приема получателя, находится onReceive()ли действие в фокусе.)

  • Должен ли получатель что-то делать, когда он виден, даже если у него нет фокуса (например, когда отображается диалог)? Если да, используйте onStart()/ onStop()(или более длительный срок службы, но опять же,onReceive() должен проверить, видна ли активность).

  • Нужно ли получателю знать о трансляции, даже если активность не видна? Например, нужно ли помнить, что что-то произошло, чтобы, когда действие стало видимым, оно могло отражать итоговое положение дел? Затем вам нужно использовать onCreate()/ onDestroy()для регистрации / отмены регистрации. (Обратите внимание, что есть и другие способы реализации такой функциональности.)

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

Также имейте в виду, что лучше сделать onPause () как можно более легким :

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

Это правда , что onDestroy()это не гарантированно будет называться , если система убивает ваш процесс в целях экономии памяти. Однако, если процесс будет остановлен, он все равно не будет получать широковещательные сообщения. В таком случае действительно ли необходимо отменять регистрацию приемников вещания?

Ларш
источник
Спасибо за ответ на мой вопрос, но ваш ответ сбивает с толку и не совсем точен. Вы говорите, что If you register in onStart(), don't also register them in onPause(), because that would be redundant: onPause() is never called without onStart() being called first.это просто нелогично и сбивает с толку, особенно когда принятый ответ совершенно точен.
jamesc
@jamesc: Ой, я имел в виду onResume, а не onPause. Вы правы, это немного сбивает с толку. Исправлено сейчас. Что касается принятого ответа, я его прокомментировал. Я считаю, что этот ответ добавляет важную и актуальную информацию, которую не предлагает принятый.
LarsH
5

Android может убить ваше приложение onStop()методом пропуска . Лучший способ решить эту проблему - зарегистрироваться BroadcastReceiverв onResume()методе и отменить регистрацию в onPause().

Ukson
источник
1
Я тоже этим занимаюсь. Были проблемы с onStop()aswell
Vygintas B
0

Вы должны зарегистрировать и отменить регистрацию вашей трансляции в методах onResume () и onPause ().

если вы зарегистрируетесь в onStart () и отмените регистрацию в onStop (). на этот раз вы получите следующую проблему.

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

Маюреш Дешмук
источник