2012-06-06 9 views
5

Recentemente ho fatto una domanda sul controllo dello stato di un SMS inviato e la risposta fornita era uno snippet di codice che registrava due "anonimi interni" (correggi la mia terminologia se è errata BroadcastReceivers per ascoltare le trasmissioni inviate/consegnate via SMS. Questi ricevitori dovevano solo ricevere i dati relativi agli SMS che la mia applicazione aveva appena inviato, quindi non era necessario ascoltarli in modo permanente.Devo annullare la registrazione di "anonymous" BroadcastReceiver

Il mio pensiero immediato è stato "bene, dovrò annullarli dopo averli terminati", ma è corretto? Ho chiesto questo poster perché non aveva incluso alcun codice di annullamento della registrazione, ma non ho ricevuto risposta. Il codice sembra essere un modo abbastanza standard per fare ciò che voglio in quanto appare su numerosi siti di sviluppo Android. Eccolo:

//---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); 

Il codice funziona correttamente.

Inoltre, non viene notificato alcun evento inviato/recapitato tramite SMS esterno alla mia app. Per esempio. Posso inviare un SMS dopo che questi BroadcastReceivers sono stati registrati e non vedo alcun messaggio Toast.

Così, ho due domande:

  1. Ho bisogno di annullare la registrazione di questi BroadcastReceivers?
  2. In caso contrario, perché no?

risposta

0

È necessario annullare la registrazione. Altrimenti, molto probabilmente si bloccherà. Ne sono abbastanza sicuro Ma se dici che non si blocca, allora, beh, hai bisogno di esaminarlo :)

Perché, Android penserà che hai dimenticato di annullare la registrazione. Si aspetta che tu annulli la registrazione. Nota: se si registra un ricevitore nell'implementazione Activity.onResume(), è necessario annullarne la registrazione in Activity.onPause(). (Non si riceveranno gli intenti quando viene messo in pausa, e ciò ridurrà il sovraccarico del sistema non necessario). annullare la registrazione in Activity.onSaveInstanceState(), perché questo non verrà chiamato se l'utente si sposta indietro nello stack della cronologia. " < ===== Dalla documentazione

+0

Perché pensi che dovrebbe andare in crash? – barry

+0

Aggiornato la mia risposta. –

+0

Bene, il codice è in un BroadcastReceiver diverso (riattivato da AlarmManager) quindi non ho alcun metodo di ciclo di vita per annullare la registrazione. Se necessario, annulliamo la registrazione di onReceive() – barry

1

Basta salvare il tuo BroadcastReceiver a un'istanza in modo che siano in grado di annullare la registrazione di esso ;-)

Basta cambiare questa linea da:

registerReceiver(new BroadcastReceiver(){ 

a:

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

Successivamente è possibile eseguire oltre:

unregisterReceiver(smsReceiver); 

Ricordarsi di salvare lo smsReceiver come membro della classe.

+0

Non penso che avrei bisogno di salvare BroadcastReceiver in un'istanza: potrei annullare la registrazione alla fine di onReceive() se necessario. Vorrei solo sapere se è necessario. Come ho detto, questo codice è disseminato in internet senza alcuna registrazione in corso! – barry

0

Quindi, se ho capito quello che hai scritto correttamente, sembra che il BroadcastReceiver dovrebbe esistere solo all'interno della chiamata sendSMS(), quindi, anche se sono registrati per i SENT o DELIVERED Intenti, essi non possono essere in giro a riceverli. Inoltre, credo che tu voglia sempre annullare la registrazione dei ricevitori quando hai finito con loro, ho visto il debugger avvisare di perdite di ricevitori.

funzionerebbe meglio se si ha parametri di classe per come sent_broadcast_receiver e delivered_broadcast_receiver che contengono un riferimento ai ricevitori che si sta registrando, in questo modo gli oggetti persistono, e può essere registrato dopo che sono fatto.

EDIT: Qualunque oggetto contiene le BroadcastReceivers per SENT e DELIVERED dovrebbe persistere fino intenti ritorno, o gli intenti (dal momento che sono PendingIntents) dovrebbe dirigere a qualcosa che può essere svegliato, se è questo ciò che desideri.

+0

Gli SMS BroadcastReceivers vengono creati in un BroadcastReceiver diverso, chiamato da AlarmManager, ad esempio, si verifica un allarme e voglio inviare un SMS in modo da eseguire lo snippet di codice nel BroadcastReceiver che è stato registrato con AlarmManager. Si consiglia di memorizzare i ricevitori come variabili in questo ricevitore in modo che persistano, ma cosa succede se il ricevitore di allarme non è in giro quando si verifica la trasmissione? Ho bisogno di un servizio? – barry

+0

Non mi riferivo a ciò che si registra con AlarmManager, ma ai costruttori "nuovo BroadcastReceiver". In realtà, non sembra esserci alcuna registrazione con AlarmManager nel tuo codice. Crea due PendingIntents per SENT e DELIVERED, registra il metodo BroadcastReceivers per quegli Intents e quindi utilizza SmsManager. –

+0

Mi dispiace ma la tua modifica non ha senso per me - "... o gli Intenti (poiché sono PendingIntents) così diretti a qualcosa che può essere svegliato, se è quello che desideri.". Puoi spiegare ulteriormente? – barry

1

Inoltre, non viene notificato alcun evento inviato/recapitato tramite SMS esterno alla mia app.

Si sta registrando dinamicamente i ricevitori. Se vuoi ascoltare intenti da altre applicazioni, devi registrare il tuo ricevitore nel file manifest. In questo modo sarà sempre attivo. E non avrai bisogno di cancellarlo.