活动泄漏了IntentReceiver

57

我正在尝试同时发送短信和邮件。发送邮件没有问题,但是当我发送短信时,我收到了这个异常:

End has leaked IntentReceiver
Are you missing a call to unregisterReceiver()? 

这是我从https://mobiforge.com/design-development/sms-messaging-android获取的代码,用于短信方法:

public class End extends Activity {
    
    Button btnSendSMS;
    EditText txtPhoneNo;
    EditText txtMessage;
    public EditText Details;
    public String user;
 
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.end);
        Details = (EditText)findViewById(R.id.details);
        btnSendSMS = (Button) findViewById(R.id.btnSend);
        Bundle b=this.getIntent().getExtras();
        final String email=b.getString("keym");
        final String pno=b.getString("keys");

        btnSendSMS.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {           
                String detail=Details.getText().toString();
                Mail m = new Mail("abc@gmail.com", "sdfsa"); 
                String[] toArr = {email}; 
                m.setTo(toArr); 
                m.setFrom("asdasd11@gmail.com"); 
                m.setSubject("EMERGENCY");
                m.setBody(detail);
             
                try { 
                    // m.addAttachment("/sdcard/filelocation"); 
                    if(m.send()) { 
                    Toast.makeText(End.this, "Email was sent successfully.", Toast.LENGTH_LONG).show(); 
                    } else { 
                  Toast.makeText(End.this, "Email was not sent.", Toast.LENGTH_LONG).show(); 
                    } 
                } catch(Exception e) { 
                //Toast.makeText(MailApp.this, "There was a problem sending the email.", Toast.LENGTH_LONG).show(); 
                Log.e("MailApp", "Could not send email", e); 
                } 
              
                sendSMS(pno, detail);
                finish();
                Intent intent = new Intent(End.this,Service.class);
                startActivity(intent);
               }   
            }
        );        
    
    } 

    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()
         {
             Context context;
             @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(){
             Context context;
             @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);    
    
}
    
}

3个回答

32

创建一个自定义的接收器,就像这样

class deliverReceiver extends BroadcastReceiver {     
@Override
 public void onReceive(Context context, 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;                        
             }

         }
}

以及一个像这样的发送和接收器...

class sentReceiver extends BroadcastReceiver {     
@Override
 public void onReceive(Context context, 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;
             }


         }

现在在sendSMS方法中执行此操作

 PendingIntent deliveredPI = PendingIntent.getBroadcast(this, 0,
         new Intent(DELIVERED), 0);
放置。
registerReceiver(sentReceiver,SENT);
registerReceiver(deliverReceiver,DELIVERED);

现在可以通过如下方式覆盖onpause并取消注册接收器:

unregisterReceiver(sentReceiver);
unregisterReceiver(deliverReceiver);

请使用以下代码:registerReceiver(sendBroadcastReceiver, new IntentFilter(SENT)) 和 registerReceiver(deliveryBroadcastReciever, new IntentFilter(DELIVERED))。 - chetan
1
嘿,这可能听起来很傻,但是如果我在我的应用程序关闭后注销接收器,那么我将无法接收到该BroadcastReceiver的意图,对吗?如果是这样,那不就失去了目的吗? - Zen
1
@alexsummers 你是在 Activity 还是 Service 中注册了 BroadcastReceiver?如果是前者,则在活动生命周期结束后,你将无法接收广播。 - Code-Apprentice
我正在使用 BroadcastReceiver 通过 Parse-SDK 接收 PushNotifications。它只在 Manifest 中注册,运行良好,但是在日志中出现了 leaked-IntentReceiver - Zen
onStart中调用registerReceiver,在onStop中调用unregisterReceiver是否有问题? - this.myself

19

您应该在onPause()中注销接收器,并在onResume()中注册它们。这样,当Android销毁并重新创建活动以进行配置更改或出于任何原因时,您仍将拥有设置好的接收器。


嘿,你能告诉我你是如何做到的吗?针对上面的那个程序! - chetan
2
为什么要在onResume()中注册它们而不是在onCreate()中? - IgorGanapolsky
1
@IgorGanapolsky 因为每次 UI 显示和隐藏时都会调用 onResumeonPause,所以您不希望在此之外监听广播。 - iceman
@IgorGanapolsky 是的,可能存在内存泄漏。 - iceman
我确实这样做了,但仍然会抛出错误。 - Neon Warge

2

1
这个答案不正确,因为onDestroy方法不能保证被调用。 - this.myself

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接