5

我最近问了一个关于检查已发送 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 发送/传递事件的通知。例如,我可以在注册后发送短信,BroadcastReceivers但看不到任何Toast消息。

所以,我有两个问题:

  1. 我需要注销这些BroadcastReceivers吗?
  2. 如果不是,为什么不呢?
4

4 回答 4

1

更重要的是,它不会收到在我的应用程序外部发生的任何 SMS 发送/传递事件的通知。

您正在动态注册接收器。如果你想监听其他应用程序的意图,你需要在清单文件中注册你的接收器。这样,它将始终处于活动状态。而且您无需取消注册。

于 2012-11-27T11:30:06.220 回答
1

只需将您保存BroadcastReceiver到一个实例,以便您可以取消注册它;-)

只需将此行更改为:

registerReceiver(new BroadcastReceiver(){

至:

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

稍后您可以执行以下操作:

unregisterReceiver(smsReceiver);

只需记住将 保存smsReceiver为班级成员。

于 2012-06-06T17:28:29.563 回答
0

所以如果我理解你写的正确的话,看起来BroadcastReceiver应该只存在于sendSMS()调用中,所以即使他们注册了SENTor DELIVEREDIntents,他们可能不会在附近接收它们。另外,我相信您在完成接收器后总是想取消注册,我已经看到调试器警告接收器泄漏。

如果您有 like 的类参数sent_broadcast_receiver并且delivered_broadcast_receiver包含对您正在注册的接收器的引用,那么它会更好地工作吗,这样对象就会持久存在,并且可以在完成后取消注册。

编辑:无论什么对象持有 BroadcastReceiversSENT并且DELIVERED应该持续到意图返回,或者 Intents(因为它们是 PendingIntents)应该指向可以被唤醒的东西,如果这是你想要的。

于 2012-06-06T17:35:22.827 回答
0

您将需要注销。否则,它很可能会崩溃。我对此非常确定。但是,如果您说它没有崩溃,那么,好吧,需要调查一下 :)

因为,Android 会认为您忘记取消注册。它希望您取消注册。“注意:如果在 Activity.onResume() 实现中注册接收器,则应在 Activity.onPause() 中取消注册。(暂停时不会收到意图,这将减少不必要的系统开销)。不要在 Activity.onSaveInstanceState() 中取消注册,因为如果用户移回历史堆栈,则不会调用它。” <===== 来自文档

于 2012-06-06T17:27:18.683 回答