Нужно ли мне отменить регистрацию «анонимного» BroadcastReceiver?

Недавно я задал вопрос о проверке состояния отправленного SMS, и ответом был фрагмент кода, который зарегистрировал два «анонимных внутренних» (пожалуйста, исправьте мою терминологию, если она неверна) BroadcastReceivers для прослушивания отправленных/доставленных SMS-рассылок. Этим приемникам требовалось только получать данные о SMS-сообщении, которое только что отправило мое приложение, поэтому от них не требовалось постоянно слушать.

Моя немедленная мысль была: «Ну, мне нужно отменить их регистрацию после того, как я закончу с ними», но правильно ли это? Я спросил об этом постера, так как он не указал никакого кода отмены регистрации, но не получил ответа. Код кажется довольно стандартным способом делать то, что я хочу, поскольку он появляется на многочисленных сайтах разработчиков Android. Вот:

//---sends an SMS message to another device---
private void sendSMS(String phoneNumber, String message)
{        
    String SENT = "SMS_SENT";
    String DELIVERED = "SMS_DELIVERED";

    PendingIntent sentPI = PendingIntent.getBroadcast(this, 0,
        new Intent(SENT), 0);

    PendingIntent deliveredPI = PendingIntent.getBroadcast(this, 0,
        new Intent(DELIVERED), 0);

    //---when the SMS has been sent---
    registerReceiver(new BroadcastReceiver(){
        @Override
        public void onReceive(Context arg0, Intent arg1) {
            switch (getResultCode())
            {
                case Activity.RESULT_OK:
                    Toast.makeText(getBaseContext(), "SMS sent", 
                            Toast.LENGTH_SHORT).show();
                    break;
                case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
                    Toast.makeText(getBaseContext(), "Generic failure", 
                            Toast.LENGTH_SHORT).show();
                    break;
                case SmsManager.RESULT_ERROR_NO_SERVICE:
                    Toast.makeText(getBaseContext(), "No service", 
                            Toast.LENGTH_SHORT).show();
                    break;
                case SmsManager.RESULT_ERROR_NULL_PDU:
                    Toast.makeText(getBaseContext(), "Null PDU", 
                            Toast.LENGTH_SHORT).show();
                    break;
                case SmsManager.RESULT_ERROR_RADIO_OFF:
                    Toast.makeText(getBaseContext(), "Radio off", 
                            Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    }, new IntentFilter(SENT));

    //---when the SMS has been delivered---
    registerReceiver(new BroadcastReceiver(){
        @Override
        public void onReceive(Context arg0, Intent arg1) {
            switch (getResultCode())
            {
                case Activity.RESULT_OK:
                    Toast.makeText(getBaseContext(), "SMS delivered", 
                            Toast.LENGTH_SHORT).show();
                    break;
                case Activity.RESULT_CANCELED:
                    Toast.makeText(getBaseContext(), "SMS not delivered", 
                            Toast.LENGTH_SHORT).show();
                    break;                        
            }
        }
    }, new IntentFilter(DELIVERED));        

    SmsManager sms = SmsManager.getDefault();
    sms.sendTextMessage(phoneNumber, null, message, sentPI, deliveredPI);

Код работает нормально.

Более того, он не получает уведомлений о каких-либо событиях отправки/доставки SMS, которые происходят вне моего приложения. Например. Я могу отправить SMS после того, как эти BroadcastReceivers будут зарегистрированы и не увижу никаких Toast сообщений.

Итак, у меня есть два вопроса:

  1. мне нужно отменить регистрацию этих BroadcastReceivers?
  2. Если нет, то почему?

person barry    schedule 06.06.2012    source источник


Ответы (4)


Просто сохраните свой BroadcastReceiver в экземпляре, чтобы вы могли отменить его регистрацию ;-)

Просто измените эту строку с:

registerReceiver(new BroadcastReceiver(){

to:

BroadcastReceiver smsReceiver=new BroadcastReceiver(){...}
registerReceiver(smsReceiver);

Позже вы можете выполнить, чем:

unregisterReceiver(smsReceiver);

Просто не забудьте сохранить smsReceiver как члена класса.

person rekire    schedule 06.06.2012
comment
Я не думаю, что мне нужно было бы сохранять BroadcastReceiver в экземпляре - при необходимости я мог бы отменить регистрацию в конце onReceive(). Я просто хотел бы знать, если это необходимо. Как я уже сказал, этот код разбросан по всему Интернету, и никакой отмены регистрации не происходит! - person barry; 06.06.2012

Более того, он не получает уведомлений о каких-либо событиях отправки/доставки SMS, которые происходят вне моего приложения.

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

person Stashi    schedule 27.11.2012

Вам нужно будет отменить регистрацию. В противном случае он, скорее всего, рухнет. Я совершенно уверен в этом. Но если вы говорите, что не крашится, то, что ж, надо разбираться :)

Потому что Android подумает, что вы забыли отменить регистрацию. Он ожидает, что вы отмените регистрацию. «Примечание. Если вы регистрируете получателя в своей реализации Activity.onResume(), вы должны отменить его регистрацию в Activity.onPause(). (Вы не будете получать намерения во время паузы, и это сократит ненужные системные накладные расходы). Не делайте этого. отменить регистрацию в Activity.onSaveInstanceState(), потому что это не будет вызываться, если пользователь вернется в стек истории». ‹===== Из документов

person Kumar Bibek    schedule 06.06.2012
comment
Почему вы думаете, что он должен рухнуть? - person barry; 06.06.2012
comment
Что ж, код находится в другом BroadcastReceiver (разбуженном AlarmManager), поэтому у меня нет никаких методов жизненного цикла для отмены регистрации. Я бы поставил отмену регистрации в конце onReceive(), если это необходимо. - person barry; 06.06.2012
comment
Это может иметь проблемы с синхронизацией, т. е. ваш приемник может быть разрегистрирован до того, как он действительно что-то получит. - person Kumar Bibek; 06.06.2012
comment
Хм... хорошо, если я отменяю регистрацию в конце onReceive(), должно быть вызвано onReceive(). т.е. должно быть, что-то получил... - person barry; 06.06.2012
comment
Ну, ваш onReceive вызывается, SMS отправляется, доставка или отправленная трансляция могли не быть отправлены до того, как вы отмените регистрацию получателя. Нет никакой гарантии. - person Kumar Bibek; 06.06.2012
comment
Ааа... Я думаю, мы говорили о разных методах onReceive(). Я бы отменил регистрацию в onReceive() методов SMS onRecieve(), а не в onReceive(), который отправляет SMS. - person barry; 06.06.2012

Итак, если я правильно понимаю, что вы написали, похоже, что BroadcastReceiver должен существовать только в вызове sendSMS(), поэтому, даже если они зарегистрированы для намерений SENT или DELIVERED, они могут не получить их. Кроме того, я считаю, что вы всегда хотите отменить регистрацию получателей, когда закончите с ними, я видел, как отладчик предупреждал об утечке приемников.

Было бы лучше, если бы у вас были параметры класса, такие как sent_broadcast_receiver и delivered_broadcast_receiver, содержащие ссылку на получателей, которые вы регистрируете, таким образом, объекты сохраняются и могут быть отменены после их завершения.

РЕДАКТИРОВАТЬ: любой объект, содержащий BroadcastReceivers для SENT и DELIVERED, должен сохраняться до тех пор, пока не вернутся намерения, или намерения (поскольку они являются PendingIntents) должны быть направлены на то, что можно разбудить, если это то, что вы хотите.

person Dandre Allison    schedule 06.06.2012
comment
SMS BroadcastReceivers создаются в другом BroadcastReceiver, который вызывается AlarmManager, т. е. возникает тревога, и я хочу отправить SMS, поэтому выполните фрагмент кода в BroadcastReceiver, который был зарегистрирован в AlarmManager. Вы предлагаете хранить приемники как переменные в этом приемнике, чтобы они сохранялись, но что, если приемника тревоги нет рядом, когда происходит трансляция? Мне нужна услуга? - person barry; 06.06.2012
comment
Я имел в виду не то, что вы регистрируете с помощью AlarmManager, а новые конструкторы BroadcastReceiver. На самом деле, похоже, что в вашем коде нет никакой регистрации в AlarmManager. Он создает два PendingIntent для SENT и DELIVERED, регистрирует область метода BroadcastReceivers для этих Intent и затем использует SmsManager. - person Dandre Allison; 06.06.2012
comment
Извините, но ваше редактирование не имеет для меня смысла - ... или намерения (поскольку они являются PendingIntents), настолько прямые к чему-то, что можно разбудить, если вы этого хотите. Не могли бы вы объяснить подробнее? - person barry; 07.06.2012