短信通知的行为

问题描述:

仪式现在我试图通过编程方式使用以下代码发送短信,但我不明白SMS SENT Receiver的行为。短信通知的行为

1)例如,如果我发送一个SMS然后Activity.RESULT_OK内部 registerReceiver正在被呼叫的3倍。如果我发送3短信使用 为loopby调用sendSMS然后Activity.RESULT_OK正在 调用9次。现在我真的不知道一个短信发送为什么这个 registerReceiver被称为这么多次?

2)此外,当我运行这段代码在模拟器我通过模拟器 端口发送短信到其他仿真这是很自然的,但是当我尝试 发送短信到一个真实的号码,然后我没有得到短信发送失败 通知,因为它通知Activity.RESULT_OK

代码发送SMS

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); 
      Log.d("SMS Service", "SMS SEND CALLED"); 
      //---when the SMS has been sent--- 
      registerReceiver(new BroadcastReceiver(){ 
       @Override 
       public void onReceive(Context arg0, Intent arg1) { 

        Log.d("SMS Service", "RECEIVE CALLED"); 
        switch (getResultCode()) 
        { 
         case Activity.RESULT_OK: 
          Toast.makeText(SMSService.this, "SMS sent", 
            Toast.LENGTH_SHORT).show(); 
          System.out.println("SMSService " + "SMS SENT"); 
          break; 
         case SmsManager.RESULT_ERROR_GENERIC_FAILURE: 
          Toast.makeText(SMSService.this, "Generic failure", 
            Toast.LENGTH_SHORT).show(); 
          System.out.println("SMSService " + "GENERIC FAILURE");       
          break; 
         case SmsManager.RESULT_ERROR_NO_SERVICE: 
          Toast.makeText(SMSService.this, "No service", 
            Toast.LENGTH_SHORT).show(); 
          System.out.println("SMSService " + "NO SERVICE"); 
          break; 
         case SmsManager.RESULT_ERROR_NULL_PDU: 
          Toast.makeText(SMSService.this, "Null PDU", 
            Toast.LENGTH_SHORT).show(); 
          System.out.println("SMSService " + "Null PDU"); 
          break; 
         case SmsManager.RESULT_ERROR_RADIO_OFF: 
          Toast.makeText(SMSService.this, "Radio off", 
            Toast.LENGTH_SHORT).show(); 
          System.out.println("SMSService " + "Radio Off"); 
          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(); 
          System.out.println("SMSService " + "SMS Delivered"); 
          break; 
         case Activity.RESULT_CANCELED: 
          Toast.makeText(getBaseContext(), "SMS not delivered", 
            Toast.LENGTH_SHORT).show(); 
          System.out.println("SMSService " + "SMS not delivered");        
          break;      
        } 
       } 
      }, new IntentFilter(DELIVERED));   

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

通常这取决于m的大小您要发送的消息 - 如果消息超过单个消息限制(在您的情况下,它听起来像是单个消息限制的约3倍),那么您将收到消息每个部分的发送和递送报告。由于您没有手动分割讯息,因此无法为每个声部指定不同的意图。

值得看看SmsManager.divideMessage()自己拆分消息,然后在SmsManager.sendMultiPartTextMessage()做实际的发送。这允许您为消息的不同部分指定不同的待定目标,因此您可以确定消息何时最终发送。

我认为模拟器将所有消息目标视为准确,并且因为没有网络可以回来并且说不然你可能不会从模拟器发送失败(除非你做了类似将模拟器放在飞机上的东西模式)。根据经验,您肯定会在真实设备上获取这些错误代码。

编辑: 它你也注册在每次发送邮件时接收思考,我用的代码有一个清单注册的接收器。有可能你已经多次注册它(它只要注册的上下文一直存在),这会多次给你 - 这也会使它重复可能9次3个消息(假设注册第三次在第一次发送完成之前完成) - 可能,但我不知道可能性如何。通过在注册的接收器中记录对象,可以相对较好地进行测试。

这是我用来发送短信代码的削减版本,它不会重复响应的消息:

ArrayList<String> split = SmsManager.getDefault().divideMessage(message); 
ArrayList<PendingIntent> success = new ArrayList<PendingIntent>(partInfo.length); 
Intent sendInt = null; 
for (int i = 0; i < partInfo.length; i++) 
{ 
    sendInt = new Intent(context.getPackageName() + RELAY_INTERNAL_RESPONSE); 
    sendInt.putExtra(KEY_MESSAGEID, messageID); 
    sendInt.putExtra(KEY_PART_NUMBER, i); 
    sendInt.putExtra(KEY_REPLY_SEND_INTENT, sendIntAction); 
    sendInt.putExtra(KEY_NUMBER, number); 
    PendingIntent sendResult = PendingIntent.getBroadcast(context, i, sendInt, PendingIntent.FLAG_ONE_SHOT); //You have to use an incrementing request code to ensure you don't just get the same pending intent. 
    success.add(sendResult); 
} 
ArrayList<PendingIntent> receipt = new ArrayList<PendingIntent>(partInfo.length); 
sendInt = new Intent(context.getPackageName() + RELAY_INTERNAL_RECEIPT); 
sendInt.putExtra(KEY_MESSAGEID, messageID); 
sendInt.putExtra(KEY_REPLY_RECEIPT_INTENT, receiptIntAction); 
sendInt.putExtra(KEY_NUMBER, number); 
PendingIntent sendResult = PendingIntent.getBroadcast(context, nextReceiptCounter(context), sendInt, PendingIntent.FLAG_ONE_SHOT); 
for (int i = 0; i < partInfo.length; i++) 
{ 
    receipt.add(sendResult); 
} 
SmsManager sm = SmsManager.getDefault(); 
sm.sendMultipartTextMessage(target, null, split, success, receipt); 

我的接收器定义:

<receiver android:name="<package>.SMSBroadcastModule" 
     android:enabled="true" 
     android:exported="false"> 
     <intent-filter> 
       <action android:name="<package>.RELAY_INTERNAL_RESPONSE" /> 
       <action android:name="<package>.RELAY_INTERNAL_RESPONSE_RECEIPT" /> 
     </intent-filter> 
</receiver> 
+0

以及我的短信文本是“John Right,这是我的简单信息!” ,所以这段文字没有那么长吧?那么仍然需要使用divideMessage? – Hunt 2012-03-13 08:26:26

+0

还有一个需要(由于HTC的bug - 这是令人讨厌的,然后它击中我的应用程序),但它不应该导致未决意图的三重响应。 – zeetoobiker 2012-03-13 09:21:10

+0

只是更新了另一种可能性和一些示例代码,至少适合我! – zeetoobiker 2012-03-13 09:36:54

或者您可以为寄存器做一个单独的类:

public class RegisterReceiverSingleton { 
private static RegisterReceiverSingleton rrS; 
public static final String SENT = "SMS_SENT"; 
public static final String DELIVERED = "SMS_DELIVERED"; 
private RegisterReceiverSingleton(final Context ctx){ 
    //when the SMS has been sent 
      ctx.registerReceiver(new BroadcastReceiver(){ 
        @Override 
        public void onReceive(Context arg0, Intent arg1) { 
         switch (getResultCode()) 
         { 
          case Activity.RESULT_OK: 
           Toast.makeText(ctx, "SMS Enviado", 
             Toast.LENGTH_SHORT).show(); 
           break; 
          case SmsManager.RESULT_ERROR_GENERIC_FAILURE: 
           Toast.makeText(ctx, "Generic failure", 
             Toast.LENGTH_SHORT).show(); 
           break; 
          case SmsManager.RESULT_ERROR_NO_SERVICE: 
           Toast.makeText(ctx, "No service", 
             Toast.LENGTH_SHORT).show(); 
           break; 
          case SmsManager.RESULT_ERROR_NULL_PDU: 
           Toast.makeText(ctx, "Null PDU", 
             Toast.LENGTH_SHORT).show(); 
           break; 
          case SmsManager.RESULT_ERROR_RADIO_OFF: 
           Toast.makeText(ctx, "Radio off", 
             Toast.LENGTH_SHORT).show(); 
           break; 
         } 
        } 
       }, new IntentFilter(SENT)); 

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

public static RegisterReceiverSingleton getInstance(final Context ctx){ 
    if(rrS==null){ 
     rrS = new RegisterReceiverSingleton(ctx); 
    } 
    return rrS; 
} 

}