Autore Topic: [Facile] Broadcast Receiver  (Letto 17111 volte)

Offline GabMarioPower

  • Moderatore globale
  • Utente senior
  • *****
  • Post: 606
  • Respect: +152
    • Github
    • Google+
    • gabrielemariotti
    • GabMarioPower
    • Mostra profilo
  • Play Store ID:
    GAB+MARIO+DEV
  • Sistema operativo:
    Ubuntu 14.04 , Win 10
[Facile] Broadcast Receiver
« il: 12 Febbraio 2013, 01:22:59 CET »
+9
Livello di difficoltà: facile
Target SDK: 17
Min SDK: 8
Link al file compresso del progetto eclipse: file in allegato

Il tutorial descrive cosa sono i Broadcast Receiver, come registrarli e come utilizzarli.

Cosa sono i Broadcast Receivers
I Broadcast Receivers sono uno dei componenti più importanti nell'architettura Android.
Questi componenti sono in ascolto di determinati messaggi, chiamati Intents Broadcast.
Per comprendere meglio la loro natura e il loro comportamento dobbiamo capire cosa sono gli Intents Broadcast .

Cosa sono gli Intents Broadcast
Gli Intents Broadcast sono un particolare tipo di Intent che vengono spediti attraverso il metodo sendBroadcast().
Vengono utilizzati per notificare alle applicazioni del sistema che sono in ascolto, determinati eventi, in modo che possano reagire.
Ogni applicazione nativa e non, può inviare questo tipo di "messaggio".
Android fa un uso molto esteso di Broadcast Intents: informazioni sulla batteria scarica, cambiamenti della connessione, chiamate e sms in arrivo sono degli Intents Broadcast.
Per inviare un Intent Broadcast sono sufficienti poche righe di codice:
Codice (Java): [Seleziona]
   public static final String INTENT_ACTION = "it.gmariotti.android.example.receiver.intent.action.TEST";
   public static final String INTENT_EXTRA  = "Extra data";
   
   Intent intent = new Intent();
   intent.setAction(INTENT_ACTION);
   intent.putExtra(INTENT_EXTRA,"test");
   sendBroadcast(intent);
Come per tutti gli intent in generale, è importante definire tre tipologie di dato : action, categorydata.
Nel nostro esempio abbiamo valorizzato solo la action, che è una stringa utilizzata per identificare l'evento, deve essere univoca, e solitamente per convenzione è formata dal nome del package.

Come implementare i Broadcast Receivers
Come detto sopra i Broadcast Receivers sono componenti in ascolto di questi tipi di messaggi.
Creare un nuovo Receiver è una operazione semplice, è sufficiente:
  • creare una classe che estende BroadcastReceiver
  • fare un override del metodo astratto onReceive
  • registrare il nostro Receiver attraverso il Manifest (staticamente) o  dinamicamente attraverso il codice
Qui sotto troviamo un esempio "vuoto":
Codice (Java): [Seleziona]
  import android.content.BroadcastReceiver;
  import android.content.Context;
  import android.content.Intent;

  public class MyTestReceiver extends BroadcastReceiver {
   
   @Override
   public void onReceive(Context context, Intent intent) {
      //TODO: React to the Intent Broadcast received.
     
   }
 }
Il metodo onReceiver() viene chiamato quando il receiver ricevono l'evento per il quale sono registrati.
Gli argomenti del metodo sono:
  • context: context attraverso il quale possiamo facilmente far partire Service o Activity
  • intent: intent che è stato inviato, e che contiene spesso informazioni aggiuntive sull'evento
Dove e perchè registrare i Broadcast Receivers
Il nostro Receiver deve poter reagire ad un determinato Intent. Per ottenere questo scopo va eseguita una registrazione.

Innanzitutto è importante capire, perchè serve la registrazione.
Il nostro Receivers, così come scritto sopra, non reagisce a nulla. Dobbiamo indicare a quale messaggio (Intent Broadcast) deve reagire. Per far questo dobbiamo definire un IntentFilter che definisce action, categorydata al quale reagire. Esattamente le stesse informazioni con cui abbiamo definito il nostro Intent.

Come indicato sopra esistono due diverse modalità di registrazione.
  • registrazione dinamica attraverso il codice
  • registrazione statica attraverso il Manifest
Come è facile intuire le due modalità non sono equivalenti; quale è meglio utilizzare?
La risposta è dipende da cosa ci voglio fare, e dove la utilizzo.
Per capire meglio questa affermazione dobbiamo capire il diverso comportamento nei due casi.

Registrazione dinamica attraverso il codice
Il Receiver quando viene registrato vive insieme al componente che l'ha registrato, e rimane in ascolto finchè il componente che l'ha registrato non viene distrutto.
Quando un Broadcast Receiver è legato alla UI di una particolare Activity, tipicamente viene registrato dinamicamente nel codice.
E' opportuno evitare di tenere in ascolto un componente quando non è utile farlo, e dobbiamo sempre ricordardi di togliere la registrazione quando non serve più.
E' anche importante sottolineare che il metodo onReceive viene eseguito nel thread UI del componente che lo registra. Questo implica che il metodo, poichè blocca l'interfaccia dovrebbe essere eseguito nel minor tempo possibile per evitare di avere l'applicazione chiusa perchè non risponde.

La registrazione avviene in questo caso nel metodo:
Codice (Java): [Seleziona]
   private IntentFilter filter =new IntentFilter(Constants.INTENT_ACTION);
   private MyTestReceiver receiver =new MyTestReceiver();

   @Override
   public void onResume() {
      super.onResume();
      // Register the broadcast receiver.
         registerReceiver(receiver, filter);
   }
   
   @Override
   public void onPause() {
      // Unregister the receiver
      unregisterReceiver(receiver);
      super.onPause();
   }

Quando si esce dall'Activity è importante togliere la registrazione, per garantire di non avere più attivo il Receiver affinchè non sia più attivo inutilmente(è importante conoscere il ciclo di vita dell'activity).

Quando il nostro receiver è registrato, se viene inviato un Intent Broadcast con una action=INTENT_ACTION, il receiver si attiva e viene eseguito il metodo onReceiver().

Registrazione attraverso il Manifest
Codice (XML): [Seleziona]
   <receiver android:name=".MyTestReceiver”>
      <intent-filter>
         <action android:name="it.gmariotti.android.example.receiver.intent.action.TEST"/>
      </intent-filter>
   </receiver>
   
In questo modo il receiver è registrato staticamente. Anche in questo caso devo specificare attraverso un Intent Filter a quale action deve reagire.

Anche qui non è opportuno avere long task nel metodo onReceiver(), ed eventualmente delegare ad un Service lunghe elaborazioni.

Esempi.
Nel nostro primo esempio, faremo una registrazione dinamica del nostro Receiver.
L'activity registra il receiver nel metodo onResume e toglie la registrazione nel metodo onPause.

Codice (Java): [Seleziona]
public class TestReceiverActivity extends Activity {

   private Button mButton;
   private MyTestReceiver mReceiver;
   
   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_test_receiver);      
      Button button= (Button) findViewById(R.id.buttonService);
      button.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View v) {            
             Intent serviceIntent=new Intent(v.getContext(),ReceiverTestService.class);
             startService(serviceIntent);
          }
      });
   }
   
   @Override
   protected void onPause() {
      unregisterReceiver( mReceiver );
      super.onPause();
   }

   @Override
   protected void onResume() {
      mReceiver=new MyTestReceiver();
      registerReceiver( mReceiver,
                    new IntentFilter(Constants.INTENT_ACTION));
      super.onResume();
   }
}

Il servizio è utilizzato esclusivamente per lanciare un Intent Broadcast con action=INTENT_ACTION.

Codice (Java): [Seleziona]
public class ReceiverTestService extends IntentService {
   
   public ReceiverTestService() {
      super("ReceiverTestService");
   }
   
   @Override
   public void onCreate() {
      super.onCreate();
      try{
         Thread.sleep(2000);
      }catch (Exception e){e.printStackTrace();}
   }

   @Override
   protected void onHandleIntent(Intent intent) {
     
      //Only for test, send a broadcast intent
      Intent mIntent= new Intent();
      mIntent.setAction(Constants.INTENT_ACTION);
      mIntent.putExtra(Constants.INTENT_EXTRA, "Additional info");
      sendBroadcast(mIntent);
   }
}

public class Constants {
    public static final String INTENT_ACTION = "it.gmariotti.android.example.receiver.intent.action.TEST";
    public static final String INTENT_EXTRA   = "Extra data";  
}

Infine il Receiver:
Codice (Java): [Seleziona]
   public class MyTestReceiver extends BroadcastReceiver {

   private static final String TAG = "MyTestReceiver";

   public MyTestReceiver() {
   }

   @Override
   public void onReceive(Context context, Intent intent) {
   
   // TODO: This method is called when the BroadcastReceiver is receiving
      // an Intent broadcast.
      Log.i(TAG, "new Intent Received ");
      Log.i(TAG, "Intent Action:" + intent.getAction());

      Set<String> categories = intent.getCategories();
      if (categories != null) {
         for (String category : intent.getCategories())
            Log.i(TAG, "new Intent Category:" + category);
      }

      if (intent.getData() != null)
         Log.i(TAG, "Intent Data:" + intent.getData().toString());

      Bundle extras = intent.getExtras();
      if (extras != null) {
         for (String key : extras.keySet()) {
            Log.i(TAG, "Intent Extra key=" + key + ":" + extras.get(key));
         }
      }

   }
}

Quando il servizio lancia l'Intent Broadcast, il nostro Receiver viene attivato e viene eseguito il metodo onReceiver().
Nel nostro esempio viene semplicemente inviato al log, le informazioni della action,categories,data ed eventuali extras contenuti nell'intent.

Questo è il log:
I/MyTestReceiver: new Intent Received
I/MyTestReceiver: Intent Action:it.gmariotti.android.example.receiver.intent.action.TEST
I/MyTestReceiver: Intent Extra key=Extra data:Additional info

In questo esempio ci siamo messi in ascolti di un nostro Intent Broadcast.
Allo stesso modo possiamo intercettare qualsiasi altro messaggio inviato dal sistema.
All'interno della classe Intent sono definiti come campi statici le action di molti degli eventi che vengono
lanciati dal sistema.

Nel nostro secondo esempio, registreremo staticamente nel Manifest un Receiver in ascolto dell'evento di sistema android.net.conn.CONNECTIVITY_CHANGE.
Codice (XML): [Seleziona]
   <receiver android:name="it.gmariotti.android.examples.receiver.ConnectivityChangeReceiver" >
         <intent-filter>
               <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
         </intent-filter>
    </receiver>

Il receiver riceve l'intent che notifica un cambiamento della connessione.

Codice (Java): [Seleziona]
public class ConnectivityChangeReceiver extends BroadcastReceiver {

   private final static String TAG="ConnectivityChangeReceiver";
   
   public ConnectivityChangeReceiver(){
      Log.i("BroadcastReceiver","INIT Receiver");
   }
   
   @Override
   public void onReceive(Context context, Intent intent) {
      Log.i("BroadcastReceiver","OnReceiver");
     
      Log.v(TAG, "action: " + intent.getAction());
      Log.v(TAG, "component: " + intent.getComponent());
      Bundle extras = intent.getExtras();
      if (extras != null) {
         for (String key : extras.keySet()) {
            Log.v(TAG, "key [" + key + "]: " + extras.get(key));
         }
      } else {
         Log.v(TAG, "no extras");
      }
   }

}

Questo è un possibile log:

I/BroadcastReceiver: INIT Receiver
I/BroadcastReceiver: OnReceiver

V/ConnectivityChangeReceiver: action: android.net.conn.CONNECTIVITY_CHANGE
V/ConnectivityChangeReceiver: component: ComponentInfo{it.gmariotti.android.examples.receiver/it.gmariotti.android.examples.receiver.ConnectivityChangeReceiver}
V/ConnectivityChangeReceiver: key [networkInfo]:
                                   NetworkInfo: type:
                           WIFI[], state: CONNECTED/CONNECTED,
                           reason: (unspecified),
                           extra: "MiWifiNetwork",
                           roaming: false,
                           failover: false,
                           isAvailable: true
V/ConnectivityChangeReceiver: key [extraInfo]: "MiWifiNetwork"
V/ConnectivityChangeReceiver: key [inetCondition]: 0
V/ConnectivityChangeReceiver: key [networkType]: 1


Sticky Broadcast Intents
Un normale Broadcast Intent dopo che viene spedito e processato dai receiver, non sono più disponibili.
Una variante sono gli sticky Broadcast Intents che sono disponibili anche al termine del broadcast.

Quando si chiama registerReceiver specificando un IntentFilter che corrisponde ad un sticky Broadcast, si ottiene l'ultimo IntentBroadcast spedito.
Un esempio è lo sticky che viene utilizzato per il cambiamento del livello della batteria.

Qui sotto un piccolo snippet:
Codice (Java): [Seleziona]
   // Register for the battery changed event
   IntentFilter battery = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
   / Intent is sticky so using null as receiver works fine
   // return value contains the status
   Intent currentBatteryCharge = registerReceiver(null, battery);

        int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);

E' importante sottolineare come in questo caso si può utilizzare null come BroadcastReceiver.

Per spedire uno Sticky Intent è sufficiente utilizzare il metodo sendStickyBroadcast(intent); e dichiarare sul Manifest
Codice (XML): [Seleziona]
<uses-permission android:name="android.permission.BROADCAST_STICKY"/>
Disabilitare e Abilitare un Broadcast Receiver registrato nel Manifest
In alcune situazioni, può essere opportuno poter disabilitare o abilitare un Receiver registrato nel Manifest.
E' in caso in cui voglio disabilitare un Receiver quando una Activity è attiva, o se voglio eseguire un Receiver una sola volta.

Il codice da utilizzare è semplice:
Codice (Java): [Seleziona]
   PackageManager pm = getPackageManager();
   ComponentName compName =
        new ComponentName(getApplicationContext(),
            ConnectivityChangeReceiver.class);
   pm.setComponentEnabledSetting(
        compName,
        PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
        PackageManager.DONT_KILL_APP);

il metodo setComponentEnabledSetting() ammette questi possibili stati:
  • COMPONENT_ENABLED_STATE_DEFAULT: mette lo stato dichiarato nel Manifest
  • COMPONENT_ENABLED_STATE_DISABLED: disabilita il componente
  • COMPONENT_ENABLED_STATE_ENABLED: abilita il componente
E' importante specificare PackageManager.DONT_KILL_APP per evitare che il PackageManager chiuda immediatamente l'app.

Esempio:
Disabilitiamo il ConnectivityChangeReceiver direttamente nel Manifest e successivamente lo abilitiamo con il codice visto sopra.

Codice (XML): [Seleziona]
<receiver
  android:name=".ConnectivityChangeReceiver"
  android:enabled="false" >
      <intent-filter>
            <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
        </intent-filter>
</receiver>

Codice (Java): [Seleziona]
   PackageManager pm = getPackageManager();
   ComponentName compName =
        new ComponentName(getApplicationContext(),
            ConnectivityChangeReceiver.class);
   pm.setComponentEnabledSetting(
        compName,
        PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
        PackageManager.DONT_KILL_APP);

Local Broadcast Manager
Nel nostro primo esempio TestReceiverActivity, abbiamo utilizzato un Intent Broadcast per inviare e ricevere dati all'interno della nostra stessa applicazione.
Questo scenario, per quanto funzionante , è migliorabile.
Se l'ambito di utilizzo degli Intent Broadcast è ristretto al solo interno della nostra applicazione, e non ha bisogno di essere esposto ad altre applicazioni esiste il LocalBroadcastManager.

Il Local Broadcast Manager permette di limitare la ricezione e la spedizione degli Intents Broadcast all'interno dei componenti della propria applicazione.
Il suo utilizzo presenta almeno due vantaggi:
  • Un Intent Broadcast è spedito all'intero sistema e dal punto di vista delle performance il LocalBroadcastManager è più efficiente di un global broadcast
  • Un Intent Broadcast globale può essere ricevuto da qualsiasi altro Riceiver. Questo rappresenta una vulnerabilità se i dati trasmessi sono sensibili
Per poter utilizzare il Local Broadcast Manager occorre:
  • utilizzare la Android Support Library
  • Recuperare un'istanza attraverso LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
  • Registrare il Receiver attraverso lbm.registerReceiver()
  • Togliere la registrazione del Receiver attraverso lbm.unregisterReceiver()
  • Spedire l'intent Broadcast attraverso lbm.sendBroadcast();
Modifichiamo il nostro primo esempio utilizzando un Local Broadcast Manager.
Codice (Java): [Seleziona]
public class LocalBroadcastActivity extends Activity {

   private Button mButton;
   private MyTestReceiver mReceiver;
   
   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_test_receiver);      
      Button button= (Button) findViewById(R.id.buttonService);
      button.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View v) {
             
             Intent serviceIntent=new Intent(v.getContext(),LocalBroadcastReceiverTestService.class);
             startService(serviceIntent);
          }
      });
   }
   
   @Override
   protected void onPause() {
      LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
      lbm.unregisterReceiver( mReceiver );
      //Important: If we don't use lbm we will retrieve   java.lang.IllegalArgumentException: Receiver not registered:

      super.onPause();
   }

   @Override
   protected void onResume() {
      LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
      mReceiver=new MyTestReceiver();
      lbm.registerReceiver( mReceiver,
                      new IntentFilter(Constants.INTENT_ACTION));
      super.onResume();
   }
}

La nostra Activity è praticamente identica alla precedente.
Le due differenze fondamentali sono nei metodi onResume() e onPause() dove viene utilizzato il lbm per registrare e togliere la registrazione.

E' importante sottolineare due aspetti.
Il Riceiver che utilizziamo è lo stesso del caso precedente. Può essere utilizzato sia per Intent globali, sia per Intent locali.
Nel onPause() dobbiamo utilizzare lbm.unregisterReceiver.
Se infatti utilizzassimo unregisterReceiver otterremo una Exception java.lang.IllegalArgumentException: Receiver not registered: che non ha bisogno di ulteriori commenti.

Codice (Java): [Seleziona]
public class LocalBroadcastReceiverTestService extends IntentService {

   
   public LocalBroadcastReceiverTestService() {
      super("ReceiverTestService");
   }
   
   @Override
   public void onCreate() {
      super.onCreate();
      try{
         Thread.sleep(2000);
      }catch (Exception e){e.printStackTrace();}
   }

   @Override
   protected void onHandleIntent(Intent intent) {
     
      //Only for test, send a broadcast intent
      Intent mIntent= new Intent();
      mIntent.setAction(Constants.INTENT_ACTION);
      mIntent.putExtra(Constants.INTENT_EXTRA, "Additional info");
      LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
      lbm.sendBroadcast(mIntent);
   }
}

Anche in questo caso il codice è identico al precedente tranne che nell'invio dell'Intent che avviene attraverso il lbm.sendBroadcast().

Il log che otteniamo è chiaramente identico a quello del primo caso, essendo il Receiver lo stesso:
I/MyTestReceiver: new Intent Received
I/MyTestReceiver: Intent Action:it.gmariotti.android.example.receiver.intent.action.TEST
I/MyTestReceiver: Intent Extra key=Extra data:Additional info


La documentazione ufficiale sul Local Broadcast Manager la trovate qui.


Ordered Broadcast
Quando un Intent viene inviato, tutti i Broadcast Receiver registrati che soddisfano la condizione del IntentFilter vengono attivati.
Se è importante l'ordine con il quale  i diversi Broadcast ricevono lo stesso Intent, possiamo utilizzare gli Ordered Broadcast.

Il metodo per lanciare un Ordered Broadcast è il seguente:
Codice (Java): [Seleziona]
   sendOrderedBroadcast(new Intent(TEST_ACTION), null);
Utilizzando questo metodo l'Intent viene spedito a tutti i Broadcast registrati nell'ordine specificato dalla proprietà android:priority specificata nel Manifest.
Un valore più alto è considerato una priorità maggiore.

Codice (XML): [Seleziona]
   <receiver android:name="it.gmariotti.android.examples.receiver.OrderReceiver1"  >
        <intent-filter android:priority="100">
              <action android:name="it.gmariotti.android.example.receiver.intent.action.TEST_ORDER" />
         </intent-filter>
   </receiver>

In genere si utilizza questa tecnica quando vogliamo eseguire i Broadcast in un determinato ordine, e vogliamo ottenere un risultato finale dall'ultimo Receiver.
Qui sotto possiamo trovare un esempio:

Registriamo 4 ricevitori nel Manifest, ognuno con la sua priorità.

Codice (XML): [Seleziona]
    <receiver android:name="it.gmariotti.android.examples.receiver.OrderReceiver1"  >
         <intent-filter android:priority="100">
              <action android:name="it.gmariotti.android.example.receiver.intent.action.TEST_ORDER" />
         </intent-filter>
    </receiver>
       
    <receiver android:name="it.gmariotti.android.examples.receiver.OrderReceiver2a"  >
          <intent-filter android:priority="200">
              <action android:name="it.gmariotti.android.example.receiver.intent.action.TEST_ORDER" />
          </intent-filter>
    </receiver>
       
    <receiver android:name="it.gmariotti.android.examples.receiver.OrderReceiver2b"  >
          <intent-filter android:priority="200">
               <action android:name="it.gmariotti.android.example.receiver.intent.action.TEST_ORDER" />
          </intent-filter>
    </receiver>
   
   <receiver android:name="it.gmariotti.android.examples.receiver.OrderReceiver3"  >
           <intent-filter android:priority="300">
               <action android:name="it.gmariotti.android.example.receiver.intent.action.TEST_ORDER" />
           </intent-filter>
    </receiver>

Creiamo una Activity che lancia un OrderedBroadcast.
L'obiettivo è far eseguire i receiver nell'ordine stabilito da android:priority e ottenere nell'ultimo Receiver un risultato.

Codice (Java): [Seleziona]
   sendOrderedBroadcast(new Intent(TEST_ACTION), null,
            new ResultReceiver(), null, 0, getString(R.string.text_initialdata1), null);

Ciascun Receiver registrato nel Manifest ha il metodo onReceiver praticamente identico.
Qui sotto viene riportato un Receiver completo.
Codice (Java): [Seleziona]
   public class OrderReceiver1 extends BroadcastReceiver {

   private static final String TAG = "OrderReceiver1";

   public OrderReceiver1() {}

   @Override
   public void onReceive(Context context, Intent intent) {
      // TODO: This method is called when the BroadcastReceiver is receiving
      // an Intent broadcast.
      Log.i(TAG, "new Intent Received 1");
      Log.i(TAG, "Intent Action:" + intent.getAction());

      if (intent.getData() != null)
         Log.i(TAG, "Intent Data:" + intent.getData().toString());
     
      Bundle extras = intent.getExtras();
      if (extras != null) {
         for (String key : extras.keySet()) {
            Log.i(TAG, "Intent Extra key=" + key + ":" + extras.get(key));
         }
      }      
      Log.i(TAG, "getResultCode() = " + getResultCode());
      Log.i(TAG, "getResultData() = " + getResultData());

      setResultCode(getResultCode() + 1);
      setResultData(getResultData() + context.getString(R.string.text_data1));
     
      Bundle resultExtras = getResultExtras(true);
      if (resultExtras != null) {
         for (String key : resultExtras.keySet()) {
            Log.i(TAG, "Result Extra key=" + key + ":" + resultExtras.get(key));
         }
         resultExtras.putString("data1", context.getString(R.string.text_data1));
      }      
      setResultExtras(resultExtras);
   }
}

Gli altri 3 riceiver sono del tutto simili.
L'unica differenza è nella riga resultExtras.putString("data1", context.getString(R.string.text_data1)).
Codice (Java): [Seleziona]
   resultExtras.putString("data1", context.getString(R.string.text_data1)); //Receiver 1
   
   resultExtras.putString("data2a", context.getString(R.string.text_data2)); //Receiver 2a
   resultExtras.putString("data2b", context.getString(R.string.text_data2)); //Receiver 2b
   
   resultExtras.putString("data3", context.getString(R.string.text_data3));  //Receiver 3

La nostra activity lancia l'ordered Broadcast utilizzando il metodo:   
Codice (Java): [Seleziona]
   public abstract void sendOrderedBroadcast(
                             Intent            intent,
                             String            receiverPermission,
                             BroadcastReceiver resultReceiver,
                             Handler           scheduler,
                             int               initialCode,
                             String            initialData,
                             Bundle            initialExtras)

Come riportato sopra:
Codice (Java): [Seleziona]
    sendOrderedBroadcast(
               new Intent(TEST_ACTION),           //Intent
            null,                                  //nessun permesso
            new ResultReceiver(),                  //Receiver finale
            null,                      
            0,                                     //Code iniziale
            getString(R.string.text_initialdata1), //Dato iniziale
            null);                                 //Extras iniziale
Ciascun receiver, nel nostro esempio, incrementa il code iniziale di 1 unità, e aggiunge al dato iniziale una propria stringa.

L'ultimo receiver, che riceverà il dato finale, è ResultReceiver così definito:
Codice (Java): [Seleziona]
    class ResultReceiver extends BroadcastReceiver {

      public void onReceive(Context context, Intent intent)
       {
           Log.d(TAG,"ResultReceiver");
           Log.d(TAG,"getResultCode() = " + getResultCode());
           Log.d(TAG,"getResultData() = " + getResultData());
         
           Bundle extras = intent.getExtras();
         if (extras != null) {
            for (String key : extras.keySet()) {
               Log.d(TAG, "key [" + key + "]: " + extras.get(key));
            }
         }
         
         Bundle resultExtras = getResultExtras(true);
         if (resultExtras != null) {
            for (String key : resultExtras.keySet()) {
               Log.i(TAG, "Result Extra key=" + key + ":" + resultExtras.get(key));
            }
         }
       }
   }

Eseguiamo il nostro codice e otteniamo questo log:


I/OrderReceiver3(11526): new Intent Received 3
I/OrderReceiver3(11526): Intent Action:it.gmariotti.android.example.receiver.intent.action.TEST_ORDER
I/OrderReceiver3(11526): getResultCode() = 0
I/OrderReceiver3(11526): getResultData() = Initial Data example 1

I/OrderReceiver2a(11526): new Intent Received 2a
I/OrderReceiver2a(11526): Intent Action:it.gmariotti.android.example.receiver.intent.action.TEST_ORDER
I/OrderReceiver2a(11526): getResultCode() = 1
I/OrderReceiver2a(11526): getResultData() = Initial Data example 1data3
I/OrderReceiver2a(11526): Result Extra key=data3:data3

I/OrderReceiver2b(11526): new Intent Received 2b
I/OrderReceiver2b(11526): Intent Action:it.gmariotti.android.example.receiver.intent.action.TEST_ORDER
I/OrderReceiver2b(11526): getResultCode() = 2
I/OrderReceiver2b(11526): getResultData() = Initial Data example 1data3data2
I/OrderReceiver2b(11526): Result Extra key=data2a:data2
I/OrderReceiver2b(11526): Result Extra key=data3:data3

I/OrderReceiver1(11526): new Intent Received 1
I/OrderReceiver1(11526): Intent Action:it.gmariotti.android.example.receiver.intent.action.TEST_ORDER
I/OrderReceiver1(11526): getResultCode() = 3
I/OrderReceiver1(11526): getResultData() = Initial Data example 1data3data2data2
I/OrderReceiver1(11526): Result Extra key=data2b:data2
I/OrderReceiver1(11526): Result Extra key=data2a:data2
I/OrderReceiver1(11526): Result Extra key=data3:data3

D/OrderedBroadcastActivity(11526): ResultReceiver
D/OrderedBroadcastActivity(11526): getResultCode() = 4
D/OrderedBroadcastActivity(11526): getResultData() = Initial Data example 1data3data2data2data1
I/OrderedBroadcastActivity(11526): Result Extra key=data2b:data2
I/OrderedBroadcastActivity(11526): Result Extra key=data1:data1
I/OrderedBroadcastActivity(11526): Result Extra key=data2a:data2
I/OrderedBroadcastActivity(11526): Result Extra key=data3:data3


L'intent viene ricevuto prima dal Receiver3, quindi dal Receiver2a, Receiver2b, Receiver1 ed infine ResultReceiver.


Broadcast Receiver e Main Thread UI
Nei paragrafi precedenti ho sottolineato come il metodo onReceive, se registrato da una Activity, viene eseguito nel thread UI principale.Questo implica che il metodo, poichè blocca l'interfaccia dovrebbe essere eseguito nel minor tempo possibile per evitare di avere l'applicazione chiusa perchè non risponde.

Qui sotto un banale esempio di cosa succede se non rispettiamo questo pattern.

Codice (Java): [Seleziona]
public class FreezingUIReceiver extends BroadcastReceiver {

   private static final String TAG = "FreezyUIReceiver";

   public FreezingUIReceiver() {}

   @Override
   public void onReceive(Context context, Intent intent) {

      Log.d(TAG, "onReceive FREEZING RECEIVER");
     
      //This is an example of WHAT NOT TO DO !!
      try{
         Thread.sleep(15000);
      }catch(Exception e){}
     
      Log.d(TAG, "FREEZING RECEIVER END");
   }  
}

Utilizzando il debug di eclipse è possibile visualizzare meglio dove viene effettivamente eseguito il metodo onReceive().
Si vede chiaramente dove viene eseguito nel Thread UI principale, determinando un blocco dell'applicazione.


Questo comportamento può portare ad un ANR ("Application Not Responding"), una delle peggior cose che può accadere ad una applicazione.
Ovviamente questo esempio è esattamente cosa non fare con un Broadcast Receiver.


I sorgenti del progetto TestReceiverProject li trovate nel file allegato, oppure su GitHub TestReceiverProject


Bibliografia:
« Ultima modifica: 01 Marzo 2013, 15:09:17 CET da GabMarioPower »

Offline Ricky`

  • Amministratore
  • Utente storico
  • *****
  • Post: 3489
  • Respect: +506
    • Github
    • Google+
    • rciovati
    • Mostra profilo
Re: [Facile] Broadcast Receiver
« Risposta #1 il: 12 Febbraio 2013, 11:57:07 CET »
0
Grazie per il tutorial ;)

A mio avviso, potresti integrare le seguenti cose:

  • Utilizzo della classe LocalBroadcastManager per mandare intent all'interno del processo
  • Utilizzo degli ordered broadcast in modo tale da dare una priorità ai receiver (tempo fa avevo creato un progettino per scriverci un tutorial a riguardo ma poi è andato a finire nella sezione "cose da fare": http://db.tt/QcdJRjvW)

Diventerebbe "la bibbia degli intents" :D
« Ultima modifica: 12 Febbraio 2013, 12:03:41 CET da Ricky` »

Offline GabMarioPower

  • Moderatore globale
  • Utente senior
  • *****
  • Post: 606
  • Respect: +152
    • Github
    • Google+
    • gabrielemariotti
    • GabMarioPower
    • Mostra profilo
  • Play Store ID:
    GAB+MARIO+DEV
  • Sistema operativo:
    Ubuntu 14.04 , Win 10
Re: [Facile] Broadcast Receiver
« Risposta #2 il: 12 Febbraio 2013, 12:53:26 CET »
+1
Grazie.

Mi hai anticipato....  :D

Stavo pensando di preparare una seconda parte.

  • LocalBroadcastManager
  • ordered broadcast
  • Intent Filter e come Android li risolve
  • Broadcast e Pending Intents


Un pò di pazienza (e di tempo) e penso di farcela  :-)

Offline GabMarioPower

  • Moderatore globale
  • Utente senior
  • *****
  • Post: 606
  • Respect: +152
    • Github
    • Google+
    • gabrielemariotti
    • GabMarioPower
    • Mostra profilo
  • Play Store ID:
    GAB+MARIO+DEV
  • Sistema operativo:
    Ubuntu 14.04 , Win 10
Re: [Facile] Broadcast Receiver
« Risposta #3 il: 18 Febbraio 2013, 17:29:30 CET »
0
Aggiornato il tutorial con la parte riguardante il Local Broadcast Manager

Offline GabMarioPower

  • Moderatore globale
  • Utente senior
  • *****
  • Post: 606
  • Respect: +152
    • Github
    • Google+
    • gabrielemariotti
    • GabMarioPower
    • Mostra profilo
  • Play Store ID:
    GAB+MARIO+DEV
  • Sistema operativo:
    Ubuntu 14.04 , Win 10
Re: [Facile] Broadcast Receiver
« Risposta #4 il: 01 Marzo 2013, 15:10:26 CET »
0
Aggiornato il tutorial con Ordered Broadcast.

Offline Sakazaki

  • Utente normale
  • ***
  • Post: 396
  • Respect: +74
    • Mostra profilo
  • Dispositivo Android:
    Sony xperia Z
  • Play Store ID:
    Saka Labs
  • Sistema operativo:
    Windows 8
Re: [Facile] Broadcast Receiver
« Risposta #5 il: 01 Marzo 2013, 15:40:23 CET »
0
Questo tutorial è semplicemente magnifico, vale tanto oro quante parole contiene  ;-)

Offline Nicola_D

  • Utente storico
  • *****
  • Post: 2479
  • SBAGLIATO!
  • Respect: +323
    • Github
    • Google+
    • nicoladorigatti
    • Mostra profilo
  • Dispositivo Android:
    Nexus 6p, Nexus 4, Nexus S, Nexus 7(2012)
  • Sistema operativo:
    Windows 7
Re: [Facile] Broadcast Receiver
« Risposta #6 il: 01 Marzo 2013, 15:49:07 CET »
0
se i politici lavorassero come fai i tutorial te.... :D
i miei complimenti
IMPORTANTE:NON RISPONDO A PROBLEMI VIA MESSAGGIO PRIVATO
LOGCAT: Non sai cos'è? -> Android Debug Bridge | Android Developers
               Dov'è in Eclipse? -> Window -> Open Prospective -> DDMS e guarda in basso!
[Obbligatorio] Logcat, questo sconosciuto! (Gruppo AndDev.it LOGTFO) - Android Developers Italia

Offline neneabc1

  • Nuovo arrivato
  • *
  • Post: 13
  • Respect: 0
    • Google+
    • Mostra profilo
  • Dispositivo Android:
    Htc One S
  • Sistema operativo:
    Android 4.1.1
Re: [Facile] Broadcast Receiver
« Risposta #7 il: 28 Marzo 2013, 17:43:55 CET »
0
Ciao a tutti..io sto sviluppando un' app e ho un problema.. spiego..
voglio controllare continuamente l'arrivo degli sms e se ne arriva uno da un numero che ho registrato in precedenza faccio delle determinate cose...
i miei problemi sono:

1)ho un'activity che chiede se attivare o meno il servizio di broadcast e non so come, da questa activity, lanciare il servizio in modo che l'app si minimizzi ma rimanga il servizio di broadcast che lavori in background

2)ad ogni avvio del telefono voglio lanciare immediatamente il servizio di broadcast (senza aprire l'activity) in modo che appunto rimanga sempre in ascolto

Quello che io chiamo servizio di broadcast non è altro che una classe:

public abstract class RicezioneSms extends BroadcastReceiver {

    private static final String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";

    @Override
    public void onReceive(Context context, Intent intent) {
        // verifico che sia arrivato un sms
       if (intent.getAction().equals(SMS_RECEIVED)) {
            Bundle bundle = intent.getExtras();
            if (bundle != null) {
                // leggo la "cartella" degli sms ricevuti
                Object[] pdus = (Object[]) bundle.get("pdus");   // pdu: protocol description unit
             
                // divido i messaggi l'uno dall'altro
                SmsMessage[] messages = new SmsMessage[pdus.length];
                StringBuilder sb = new StringBuilder();
                for (int i=0; i<pdus.length; i++) {
                   
                    // controllo che il messaggio arrivato sia dal numero associato
                    if( SmsMessage.createFromPdu((byte[]) pdus).getOriginatingAddress() == MainActivity.phoneNum ){
                       
                        //leggo il testo del messaggio e in base al codice eseguo l'operazione
                       if( SmsMessage.createFromPdu((byte[]) pdus).getMessageBody() == "00" ){   
                          
                                 /////////////////////////////////////////////////////
                       }
                       if( SmsMessage.createFromPdu((byte[]) pdus).getMessageBody() == "01" ){
                       
                           /////////////////////////////////////////////////////   
                   
                   }
                       if( SmsMessage.createFromPdu((byte[]) pdus).getMessageBody() == "10" ){   
                       
                          /////////////////////////////////////////////////////   
                       
                       }else{
                   
                          /////////////////////////////////////////////////////   
                       
                       }
                    }
                }             
            }
        }
    }
}

Se qualcuno riuscisse a spiegarmi come risolvere i due punti sopra...gliene sarei davvero grato   ;-)
 

Offline pegaso993

  • Utente junior
  • **
  • Post: 84
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    note 2
  • Sistema operativo:
    android
Re: [Facile] Broadcast Receiver
« Risposta #8 il: 04 Ottobre 2013, 21:18:56 CEST »
0
il codice per disattivare le notifiche è il seguente ?
cioe io ho un server dove si registrano l utente per disattivare le notifiche spunta il ceckbox
quindi se uso n if più questo codice riesco a disattivare

Codice (ActionScript): [Seleziona]
 PackageManager pm = getPackageManager();
   ComponentName compName =
        new ComponentName(getApplicationContext(),
            ConnectivityChangeReceiver.class);
   pm.setComponentEnabledSetting(
        compName,
        PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
        PackageManager.DONT_KILL_APP);

Offline tonno16

  • Utente storico
  • *****
  • Post: 1197
  • Respect: +58
    • Mostra profilo
  • Dispositivo Android:
    moto g
  • Play Store ID:
    Diego Tonini
  • Sistema operativo:
    OpenSuse
Re: [Facile] Broadcast Receiver
« Risposta #9 il: 22 Maggio 2015, 09:49:58 CEST »
0
Ho un dubbio. Devo comunicare ad un Activity qualcosa. Devo farlo ogni secondo. E' giusto usare sendBroadcast() passando l'intent?
Il mio intent può avere 6 action diverse. Dovrei registrare gli stessi action nel manifest?
Lo chiedo perchè mi viene un dubbio quando nell' activity faccio registerReceiver(mReceiver,new IntentFilter(action));
Non so che action mettere

Offline GabMarioPower

  • Moderatore globale
  • Utente senior
  • *****
  • Post: 606
  • Respect: +152
    • Github
    • Google+
    • gabrielemariotti
    • GabMarioPower
    • Mostra profilo
  • Play Store ID:
    GAB+MARIO+DEV
  • Sistema operativo:
    Ubuntu 14.04 , Win 10
Re: [Facile] Broadcast Receiver
« Risposta #10 il: 25 Maggio 2015, 20:32:09 CEST »
0
Ho un dubbio. Devo comunicare ad un Activity qualcosa. Devo farlo ogni secondo. E' giusto usare sendBroadcast() passando l'intent?

Dipende dal contesto.

Offline tonno16

  • Utente storico
  • *****
  • Post: 1197
  • Respect: +58
    • Mostra profilo
  • Dispositivo Android:
    moto g
  • Play Store ID:
    Diego Tonini
  • Sistema operativo:
    OpenSuse
Re: [Facile] Broadcast Receiver
« Risposta #11 il: 25 Maggio 2015, 20:37:47 CEST »
0
Ho perfezionato. Diciamo che ho cambiato approccio. Mi serve solo quando l' acticity è visibile. Quindi tutto OK ;)

Offline MarcoMOSX

  • Nuovo arrivato
  • *
  • Post: 8
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    LG G2
  • Sistema operativo:
    Android 4.2.2
Re: [Facile] Broadcast Receiver
« Risposta #12 il: 11 Luglio 2015, 18:10:42 CEST »
0
ciao a tutti, complimenti per il tutorial.
Io sto cercando di usare un broadcast receiver per ascoltare le chiamate in arrivo, le mie classi sono:
Activity con button per avviare un service che dovrebbe tenere attivo il Broadcast receiver:
Codice (Java): [Seleziona]
public class Chiamata extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_chiamata);
        Button segreteria_on = (Button) findViewById(R.id.segreteria_on);
        segreteria_on.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent ascolto = new Intent(getBaseContext(),MiMettoInAscolto.class);
                startService(ascolto);
            }
        });
    }


}

Il service:
Codice (Java): [Seleziona]
public class MiMettoInAscolto extends Service {
    public MiMettoInAscolto() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        Intent ascolto = new Intent();
        ascolto.setAction(TELEPHONY_SERVICE);
        sendStickyBroadcast(ascolto);
        AscoltoLeChiamate ricevo_le_chiamate = new AscoltoLeChiamate();
        registerReceiver(ricevo_le_chiamate, new IntentFilter(TELEPHONY_SERVICE));
        Toast.makeText(getBaseContext(),"Stonelloservice",Toast.LENGTH_SHORT).show();
        throw new UnsupportedOperationException("Not yet implemented");
    }
}

Il BroadcastReceiver:
Codice (Java): [Seleziona]
public class AscoltoLeChiamate extends BroadcastReceiver {
    public AscoltoLeChiamate() {
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO: This method is called when the BroadcastReceiver is receiving
        // an Intent broadcast.
        TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        telephonyManager.listen(new CustomPhoneStateListener(context), PhoneStateListener.LISTEN_CALL_STATE);
        throw new UnsupportedOperationException("Not yet implemented");
    }
}

e la classe CustomPhoneStateListener:
Codice (Java): [Seleziona]
public class CustomPhoneStateListener extends PhoneStateListener {

    //private static final String TAG = "PhoneStateChanged";
    Context context; //Context to make Toast if required
    public CustomPhoneStateListener(Context context) {
        super();
        this.context = context;
    }

    @Override
    public void onCallStateChanged(int state, String incomingNumber) {
        super.onCallStateChanged(state, incomingNumber);

        switch (state) {
            case TelephonyManager.CALL_STATE_IDLE:
                //when Idle i.e no call
                Toast.makeText(context, "Phone state Idle", Toast.LENGTH_LONG).show();
                break;
            case TelephonyManager.CALL_STATE_OFFHOOK:
                //when Off hook i.e in call
                //Make intent and start your service here
                Toast.makeText(context, "Phone state Off hook", Toast.LENGTH_LONG).show();
                break;
            case TelephonyManager.CALL_STATE_RINGING:
                //when Ringing
                Toast.makeText(context, "Phone state Ringing", Toast.LENGTH_LONG).show();
                break;
            default:
                break;
        }
    }
}
Ho provato anche con un IntentService ma mi da errore, ecco la classe:
Codice (Java): [Seleziona]
public class MimettoInAscoltoIntent extends IntentService {
    // TODO: Rename actions, choose action names that describe tasks that this
    // IntentService can perform, e.g. ACTION_FETCH_NEW_ITEMS
    private static final String ACTION_FOO = "com.provedafare.mmosx.segreteria.action.FOO";
    private static final String ACTION_BAZ = "com.provedafare.mmosx.segreteria.action.BAZ";

    // TODO: Rename parameters
    private static final String EXTRA_PARAM1 = "com.provedafare.mmosx.segreteria.extra.PARAM1";
    private static final String EXTRA_PARAM2 = "com.provedafare.mmosx.segreteria.extra.PARAM2";

    /**
     * Starts this service to perform action Foo with the given parameters. If
     * the service is already performing a task this action will be queued.
     *
     * @see IntentService
     */

    // TODO: Customize helper method
    public static void startActionFoo(Context context, String param1, String param2) {
        Intent intent = new Intent(context, MimettoInAscoltoIntent.class);
        intent.setAction(ACTION_FOO);
        intent.putExtra(EXTRA_PARAM1, param1);
        intent.putExtra(EXTRA_PARAM2, param2);
        context.startService(intent);
    }

    /**
     * Starts this service to perform action Baz with the given parameters. If
     * the service is already performing a task this action will be queued.
     *
     * @see IntentService
     */

    // TODO: Customize helper method
    public static void startActionBaz(Context context, String param1, String param2) {
        Intent intent = new Intent(context, MimettoInAscoltoIntent.class);
        intent.setAction(ACTION_BAZ);
        intent.putExtra(EXTRA_PARAM1, param1);
        intent.putExtra(EXTRA_PARAM2, param2);
        context.startService(intent);
    }

    public MimettoInAscoltoIntent() {
        super("MimettoInAscoltoIntent");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        if (intent != null) {
            final String action = intent.getAction();
            if (ACTION_FOO.equals(action)) {
                final String param1 = intent.getStringExtra(EXTRA_PARAM1);
                final String param2 = intent.getStringExtra(EXTRA_PARAM2);
                handleActionFoo(param1, param2);
            } else if (ACTION_BAZ.equals(action)) {
                final String param1 = intent.getStringExtra(EXTRA_PARAM1);
                final String param2 = intent.getStringExtra(EXTRA_PARAM2);
                handleActionBaz(param1, param2);
            }
        }

        Toast.makeText(getBaseContext(),"Sono nel service", Toast.LENGTH_SHORT).show();
        Intent ascolto = new Intent();
        ascolto.setAction(TELEPHONY_SERVICE);
        sendStickyBroadcast(ascolto);
        AscoltoLeChiamate ricevo_le_chiamate = new AscoltoLeChiamate();
        registerReceiver(ricevo_le_chiamate, new IntentFilter(TELEPHONY_SERVICE));
        Toast.makeText(getBaseContext(),"Stonelloservice",Toast.LENGTH_SHORT).show();
    }

    /**
     * Handle action Foo in the provided background thread with the provided
     * parameters.
     */

    private void handleActionFoo(String param1, String param2) {
        // TODO: Handle action Foo
        throw new UnsupportedOperationException("Not yet implemented");
    }

    /**
     * Handle action Baz in the provided background thread with the provided
     * parameters.
     */

    private void handleActionBaz(String param1, String param2) {
        // TODO: Handle action Baz
        throw new UnsupportedOperationException("Not yet implemented");
    }
}
L'errore è:
Codice (XML): [Seleziona]
07-11 18:04:49.636  20205-20323/com.provedafare.mmosx.chiamata E/AndroidRuntime﹕ FATAL EXCEPTION: IntentService[MimettoInAscoltoIntent]
    Process: com.provedafare.mmosx.chiamata, PID: 20205
    java.lang.SecurityException: Permission Denial: broadcastIntent() requesting a sticky broadcast from pid=20205, uid=10166 requires android.permission.BROADCAST_STICKY
            at android.os.Parcel.readException(Parcel.java:1540)
            at android.os.Parcel.readException(Parcel.java:1493)
            at android.app.ActivityManagerProxy.broadcastIntent(ActivityManagerNative.java:2803)
            at android.app.ContextImpl.sendStickyBroadcast(ContextImpl.java:1532)
            at android.content.ContextWrapper.sendStickyBroadcast(ContextWrapper.java:454)
            at com.provedafare.mmosx.chiamata.MimettoInAscoltoIntent.onHandleIntent(MimettoInAscoltoIntent.java:78)
            at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:135)
            at android.os.HandlerThread.run(HandlerThread.java:61)
ed il manifest è:
Codice (XML): [Seleziona]
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="com.provedafare.mmosx.chiamata" >

    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="ANDROID.PERMISSION.CALL_PRIVILEGED" />
    <uses-permission android:name="ANDROID.PERMISSION.READ_CALL_LOG" />
    <uses-permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="ANDROID.PERMISSION.BROADCAST_STICKY" />

    <application
       android:allowBackup="true"
       android:icon="@mipmap/ic_launcher"
       android:label="@string/app_name"
       android:theme="@style/AppTheme" >
        <activity
           android:name=".Chiamata"
           android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <receiver
           android:name=".AscoltoLeChiamate"
           android:enabled="true"
           android:exported="true" >
        </receiver>

        <service
           android:name=".MiMettoInAscolto"
           android:enabled="true"
           android:exported="true" >
        </service>
        <service
           android:name=".MimettoInAscoltoIntent"
           android:exported="false" >
        </service>
    </application>

</manifest>
Quando avvio il service teoricamente per come l'ho pensata io dovrebbe uscire un toast che mi dice che il cell non ha chiamate in ingresso.
Potreste dirmi perché non esce nessun toast e non riesco quindi a capire se la mia app funziona o meno.

Grazie mille in anticipo a tutti.

Offline tonno16

  • Utente storico
  • *****
  • Post: 1197
  • Respect: +58
    • Mostra profilo
  • Dispositivo Android:
    moto g
  • Play Store ID:
    Diego Tonini
  • Sistema operativo:
    OpenSuse
Re: [Facile] Broadcast Receiver
« Risposta #13 il: 11 Luglio 2015, 18:14:56 CEST »
0
nel manifest vanno bene i permetti in maiuscolo? Non ho mai provato. Inoltre è normale che lanci cosi tante eccezioni? tipo in OnBind. Una volta che viene effettuato il bind viene lanciata un eccezione. Per quale motivo?

Post unito: 11 Luglio 2015, 18:25:50 CEST
Ora che guardo meglio, oltre a quello che ho già scritto, ti aspetteresti il toast quando viene fatto il bind, che è asincrono. Oltre a fare startService, dovresti fare bindService.
Ma sicuro che ti serva un BoundService? Un bound service lo usi quando vuoi chiamare metodi diretti del service.
« Ultima modifica: 11 Luglio 2015, 18:25:50 CEST da tonno16, Reason: Merged DoublePost »

Offline MarcoMOSX

  • Nuovo arrivato
  • *
  • Post: 8
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    LG G2
  • Sistema operativo:
    Android 4.2.2
Re: [Facile] Broadcast Receiver
« Risposta #14 il: 11 Luglio 2015, 18:57:30 CEST »
0
Ho provato anche con un Intent Service, in pratica a me serve che una volta che la mia activity lancia il servizio questo rimanga attivo in background fino a quando non riapro l'activity e lo fermo io.
Spero sia chiaro, purtroppo è tutto il giorno che ci sbatto ma non sto riuscendo a farlo.
Aggiungo:
Avevo pensato che potrei segnalare la presenza del service in background tramite una notifica nella barra, solo che quando provo a crearne una seguendo il codice di developer.google.com mi da errore su
Codice (Java): [Seleziona]
NotificationCompat.Builder mBuilder =
    new NotificationCompat.Builder(this)
mi dice che non trova e che non esiste NotificatioCompat
Bah...
Spero mi possiate aiutare vivamente.
« Ultima modifica: 11 Luglio 2015, 19:01:02 CEST da MarcoMOSX »