giovedì 15 settembre 2011

ANDROID : Comunicazione tra Service e Activity

In molti si pongono il problema di come far comunicare un Service con una Activity. Quante volte vi è capitato di voler modificare una view, in seguito ad un evento che avete gestito nel Service?
Vi illustro come non sia nulla di complicato. Nell'esempio, il Service manda messaggi (di errore) alla Activity, la quale li mostrerà a schermo. Si farà uso del BroadcastReceiver.

Nell'Activity.
Dovrete creare il vostro Receiver che estende il BroadcastReceiver (al di fuori del metodo onCreate), ed ovviamente dichiararlo nelle variabili. Quindi :

Tra le variabili inseriamo :
private MessaggiReceiver messaggiReceiver;
TextView txtError;

Dopo l'onCreate creiamo il nostro Receiver e quindi estendiamo il BroadcastReceiver. Nell'onReceive, esaminiamo l'oggetto che ci viene passato nell'intent. In questo caso verifichiamo se sia il caso di login sbagliato, in caso affermativo, andiamo a modificare la nostra textView, visualizzando il messaggio di errore :
 private class MessaggiReceiver extends BroadcastReceiver {
     @Override
     public void onReceive(Context context, Intent intent) {
         if (intent.getAction().equals(Constants.LOGIN_KO)) {
          txtError.setText(Constants.LOGIN_KO);
         }         
     }
 }

 Constants è una semplice classe in cui ci sono stringhe statiche:

public class Constants {
    public static final String NO_URL = "Url not found";
    public static final String LOGIN_KO = "Bad user or password, try again";
    public static final String SERVICE_KO = "Service unavailable";
}

Tornando alla nostra activity, bisognerà fare anche l'ovveride dell'onResume e dell'onPause, per dire al nostro Receiver come comportarsi. In particolare nell'intent-filter aggiungiamo le action su cui "rimaniamo in ascolto". Quindi :

    @Override
    public void onResume(){
        if (messaggiReceiver == null)
            messaggiReceiver = new MessaggiReceiver();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Constants.LOGIN_KO);
        intentFilter.addAction(Constants.NO_URL);
        intentFilter.addAction(Constants.ERROR_GEN);
        registerReceiver(messaggiReceiver, intentFilter);
        super.onResume();
    }
   
    @Override
    public void onPause(){
        if (messaggiReceiver != null) unregisterReceiver(messaggiReceiver);
        super.onPause();
    }

La nostra Activity è a posto così. All'arrivo di una action di quelle gestite, partirà il Receiver che modificherà la textView. Ovviamente la textView dovrete assegnarla nell'onCreate con il solito:

txtError = (TextView)findViewById(R.id.TextError);

Passiamo al Service.
Per chiamare il nostro Receiver al verificarsi di un evento basta la semplice chiamata sendBroadcast, passando una delle action che abbiamo gestito prima.
Quindi ad esempio :

if (!"OK".equalsIgnoreCase(esitoLogin)){    
    sendBroadcast(new Intent(Constants.LOGIN_KO));
    return START_STICKY;
}

That's All.

1 commento:

Franco ha detto...

Ottimo post, mi ha fatto capire molte cose.
Aggiungo però una domanda: come faccio con una stringa variabile che il service calcola, o riceve dal web, e invia all'activity?
Grazie