Panoramica dei servizi associati

Un servizio associato è il server in un'interfaccia client-server. Consente ai componenti come attività associate al servizio, inviare richieste, ricevere risposte ed eseguire comunicazione tra processi (IPC, Inter-Process Communication). In genere un servizio associato rimane attivo solo mentre ne serve un altro dell'applicazione e non viene eseguita in background a tempo indeterminato.

Questo documento descrive come creare un servizio associato, incluse le modalità di associazione al servizio da altri componenti dell'applicazione. Per ulteriori informazioni sui servizi in ad esempio come recapitare notifiche da un servizio e impostare il servizio per l'esecuzione in primo piano, fai riferimento ai Panoramica dei servizi.

Nozioni di base

Un servizio associato è un'implementazione della classe Service che consente che altre applicazioni si collegano e interagiscono con quest'ultimo. Per specificare l'associazione per un implementi il metodo di callback onBind(). Questo restituisce un oggetto IBinder che definisce l'interfaccia di programmazione che che i client possono usare per interagire con il servizio.

Associazione a un servizio avviato

Come spiegato nella Panoramica dei servizi, puoi creare un servizio avviato e associato. Vale a dire che puoi avviare di servizio chiamando startService(), che consente viene eseguito a tempo indeterminato. Puoi anche consentire a un client di associarsi al servizio chiamata bindService().

Se consenti l'avvio e l'associazione del servizio, all'avvio del servizio Il sistema non elimina il servizio quando tutti i client vengono slegati. Devi invece interrompere esplicitamente il servizio chiamando stopSelf() o stopService().

Anche se di solito implementi onBind() o onStartCommand(), a volte capita necessario per implementarle entrambe. Ad esempio, per un music player potrebbe essere utile consentire l'esecuzione del suo servizio a tempo indeterminato e come vincolanti. In questo modo, un'attività può avviare il servizio per riprodurre che continuerà a essere riprodotta anche se l'utente esce dall'applicazione. Quindi, quando l'utente all'applicazione, l'attività può associarsi al servizio per riprendere il controllo per riprodurre un video.

Per saperne di più sul ciclo di vita dei servizi quando aggiungi l'associazione a un servizio avviato, consulta la sezione Gestire il ciclo di vita di un servizio associato.

Un client si collega a un servizio chiamando bindService(). Quando succede, deve fornire un'implementazione di ServiceConnection, che monitora la connessione al servizio. Il valore restituito bindService() indica se le proprietà servizio richiesto e se il client è autorizzato ad accedervi.

Quando il sistema Android crea la connessione tra il client e il servizio, chiama onServiceConnected() il giorno ServiceConnection. La Il metodo onServiceConnected() include un IBinder , che il client utilizzerà per comunicare con il servizio associato.

Puoi collegare più client a un servizio contemporaneamente. Tuttavia, di sistema memorizza nella cache il canale di comunicazione del servizio IBinder. In altre parole, il sistema chiama l'elemento onBind() del servizio per generare IBinder solo quando il primo vincoli client. Il sistema invia quindi lo stesso IBinder a tutti i client aggiuntivi che si associano allo stesso servizio, senza chiamare onBind() di nuovo.

Quando l'ultimo client si scollega dal servizio, il sistema elimina il servizio, a meno che il parametro è stato avviato utilizzando startService().

La parte più importante dell'implementazione del servizio associato è la definizione dell'interfaccia restituito dal metodo di callback onBind(). Le seguenti illustra i diversi modi in cui è possibile definire interfaccia di IBinder.

Crea un servizio associato

Quando crei un servizio che fornisce l'associazione, devi fornire un valore IBinder che fornisce l'interfaccia di programmazione che i client possono utilizzare per interagire con il servizio. Là puoi definire l'interfaccia in tre modi:

Ampliare la classe Binder
Se il servizio è privato per la tua applicazione e viene eseguito nello stesso processo come client, cosa comune, per creare la tua interfaccia estendendo Binder classe e la restituzione di un'istanza onBind(). Il cliente riceve i Binder e puoi usarlo per accedere direttamente ai metodi pubblici disponibili in Binder implementazione o Service.

Questa è la tecnica preferita quando il tuo servizio è semplicemente un worker in background per il tuo un'applicazione. L'unico caso d'uso quando questo non è il modo migliore per creare l'interfaccia è se il servizio è utilizzato da altre applicazioni o in processi separati.

Utilizzare un Messenger
Se hai bisogno che la tua interfaccia funzioni su diversi processi, puoi creare un'interfaccia per il servizio con un Messenger. In questo modo, il servizio definisce un Handler che risponde a diversi tipi di oggetti Message.

Questo Handler è la base per un Messenger che può quindi condividere un IBinder con il client, consentendo al client di inviare comandi al servizio utilizzando oggetti Message. Inoltre, il cliente può definire un valore Messenger per far sì che il servizio possa inviare messaggi.

Questo è il modo più semplice per eseguire la comunicazione tra processi (IPC), perché Messenger mette in coda tutte le richieste in un singolo thread in modo che non sia necessario progettare il tuo servizio sia sicuro per i thread.

Usa il modello AIDL
Android Interface Definition Language (AIDL) scompone gli oggetti in che il sistema operativo è in grado di comprendere e le esegue il marshall tra i processi per l'esecuzione IPC. La tecnica precedente, utilizzando un Messenger, si basa in realtà sull'AIDL come la sua struttura sottostante.

Come accennato nella sezione precedente, Messenger crea una coda di tutte le richieste del client in un singolo thread, quindi il servizio riceve le richieste una alla volta. Se Se però vuoi che il servizio gestisca più richieste contemporaneamente, puoi usare AIDL strato Add. In questo caso, il servizio deve essere sicuro per i thread e in grado di eseguire il multi-threading.

Per usare direttamente l'AIDL, crea un file .aidl che definisce l'interfaccia di programmazione. Gli strumenti SDK per Android utilizzano questo file per generare una classe astratta che implementa l'interfaccia e gestisce l'IPC, può quindi estendersi all'interno del tuo servizio.

Nota: per la maggior parte delle applicazioni, AIDL non è la scelta migliore per creare un servizio associato, perché potrebbe richiedere funzionalità di multi-threading può comportare un'implementazione più complicata. Pertanto, il presente documento non tratta di come per utilizzarlo per il tuo servizio. Se hai la certezza di aver bisogno per utilizzare direttamente l'AIDL, consulta l'articolo AIDL documento.

Estendi la classe Binder

Se solo l'applicazione locale utilizza il tuo servizio e non è necessario lavorare tra i vari processi, puoi implementare la tua classe Binder che fornisce al cliente ai metodi pubblici nel servizio.

Nota: questo funziona solo se il client e il servizio sono nello stesso servizio un'applicazione e un processo, che è il più comune. Ad esempio, questa soluzione funziona bene per un che deve associare al proprio servizio un'attività che riproduce musica nel sfondo.

Ecco come impostarlo:

  1. Nel tuo servizio, crea un'istanza di Binder che uno dei seguenti:
    • Contiene metodi pubblici che il client può chiamare.
    • Restituisce l'istanza Service corrente, che dispone di metodi pubblici che il cliente può chiamare.
    • Restituisce un'istanza di un'altra classe ospitata dal servizio con metodi pubblici che che il cliente può chiamare.
  2. Restituisci questa istanza di Binder dal metodo di callback onBind().
  3. Nel client, ricevi Binder dal metodo di callback onServiceConnected() e effettuare chiamate al servizio associato utilizzando i metodi forniti.

Nota: il servizio e il client devono essere nello stesso account in modo che il client possa trasmettere l'oggetto restituito e chiamare correttamente le relative API. Il servizio e il client devono essere nello stesso processo, perché questa tecnica non esegue alcuna il marshalling tra i processi.

Ad esempio, ecco un servizio che fornisce ai clienti accesso ai metodi nel servizio tramite un'implementazione Binder:

Kotlin

class LocalService : Service() {
    // Binder given to clients.
    private val binder = LocalBinder()

    // Random number generator.
    private val mGenerator = Random()

    /** Method for clients.  */
    val randomNumber: Int
        get() = mGenerator.nextInt(100)

    /**
     * Class used for the client Binder. Because we know this service always
     * runs in the same process as its clients, we don't need to deal with IPC.
     */
    inner class LocalBinder : Binder() {
        // Return this instance of LocalService so clients can call public methods.
        fun getService(): LocalService = this@LocalService
    }

    override fun onBind(intent: Intent): IBinder {
        return binder
    }
}

Java

public class LocalService extends Service {
    // Binder given to clients.
    private final IBinder binder = new LocalBinder();
    // Random number generator.
    private final Random mGenerator = new Random();

    /**
     * Class used for the client Binder.  Because we know this service always
     * runs in the same process as its clients, we don't need to deal with IPC.
     */
    public class LocalBinder extends Binder {
        LocalService getService() {
            // Return this instance of LocalService so clients can call public methods.
            return LocalService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    /** Method for clients. */
    public int getRandomNumber() {
      return mGenerator.nextInt(100);
    }
}

LocalBinder fornisce il metodo getService() per consentire ai clienti di recuperare i l'istanza attuale di LocalService. In questo modo i client possono chiamare metodi pubblici completamente gestito di Google Cloud. Ad esempio, i clienti possono chiamare getRandomNumber() dal servizio.

Ecco un'attività che si collega a LocalService e chiama getRandomNumber() Quando un utente fa clic su un pulsante:

Kotlin

class BindingActivity : Activity() {
    private lateinit var mService: LocalService
    private var mBound: Boolean = false

    /** Defines callbacks for service binding, passed to bindService().  */
    private val connection = object : ServiceConnection {

        override fun onServiceConnected(className: ComponentName, service: IBinder) {
            // We've bound to LocalService, cast the IBinder and get LocalService instance.
            val binder = service as LocalService.LocalBinder
            mService = binder.getService()
            mBound = true
        }

        override fun onServiceDisconnected(arg0: ComponentName) {
            mBound = false
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)
    }

    override fun onStart() {
        super.onStart()
        // Bind to LocalService.
        Intent(this, LocalService::class.java).also { intent ->
            bindService(intent, connection, Context.BIND_AUTO_CREATE)
        }
    }

    override fun onStop() {
        super.onStop()
        unbindService(connection)
        mBound = false
    }

    /** Called when a button is clicked (the button in the layout file attaches to
     * this method with the android:onClick attribute).  */
    fun onButtonClick(v: View) {
        if (mBound) {
            // Call a method from the LocalService.
            // However, if this call is something that might hang, then put this request
            // in a separate thread to avoid slowing down the activity performance.
            val num: Int = mService.randomNumber
            Toast.makeText(this, "number: $num", Toast.LENGTH_SHORT).show()
        }
    }
}

Java

public class BindingActivity extends Activity {
    LocalService mService;
    boolean mBound = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    @Override
    protected void onStart() {
        super.onStart();
        // Bind to LocalService.
        Intent intent = new Intent(this, LocalService.class);
        bindService(intent, connection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        unbindService(connection);
        mBound = false;
    }

    /** Called when a button is clicked (the button in the layout file attaches to
      * this method with the android:onClick attribute). */
    public void onButtonClick(View v) {
        if (mBound) {
            // Call a method from the LocalService.
            // However, if this call is something that might hang, then put this request
            // in a separate thread to avoid slowing down the activity performance.
            int num = mService.getRandomNumber();
            Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
        }
    }

    /** Defines callbacks for service binding, passed to bindService(). */
    private ServiceConnection connection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className,
                IBinder service) {
            // We've bound to LocalService, cast the IBinder and get LocalService instance.
            LocalBinder binder = (LocalBinder) service;
            mService = binder.getService();
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            mBound = false;
        }
    };
}

L'esempio precedente mostra in che modo il client si associa al servizio utilizzando un'implementazione ServiceConnection e il callback onServiceConnected(). Il prossimo fornisce ulteriori informazioni su questo processo di associazione al servizio.

Nota: nell'esempio precedente, onStop() slega il client dal servizio. Svincola i clienti dai servizi nei momenti opportuni, come illustrato nelle Note aggiuntive.

Per altro codice di esempio, consulta LocalService.java e LocalServiceActivities.java in ApiDemos.

Utilizzare un Messenger

Se hai bisogno che il tuo servizio comunichi con i processi remoti, puoi utilizzare un Messenger per fornire l'interfaccia per il tuo servizio. Questa tecnica consente esegui la comunicazione inter-process (IPC) senza dover usare AIDL.

L'utilizzo di un Messenger per l'interfaccia più semplice rispetto all'utilizzo di AIDL perché Messenger mette in coda tutte le chiamate al servizio. Un'interfaccia AIDL pura invia richieste simultanee al che deve quindi gestire il multithreading.

Per la maggior parte delle applicazioni, il servizio non richiede il multi-threading, quindi l'utilizzo di un'Messenger consente al servizio di gestire una chiamata alla volta. Se è importante in modo che il tuo servizio sia multithread, usa AIDL per definire l'interfaccia.

Ecco un riepilogo di come utilizzare un Messenger:

  1. Il servizio implementa un Handler che riceve un callback per ogni una chiamata da un cliente.
  2. Il servizio utilizza Handler per creare un Messenger oggetto (che è un riferimento a Handler).
  3. Messenger crea un IBinder che il servizio i resi ai clienti da onBind().
  4. I client utilizzano IBinder per creare un'istanza di Messenger (che fa riferimento al Handler del servizio), che il client utilizza per inviare Message oggetti al servizio.
  5. Il servizio riceve ogni Message nel suo Handler, in particolare nel metodo handleMessage().

In questo modo, il client non avrà metodi per chiamare il servizio. Invece, Il client recapita i messaggi (Message oggetti) che il servizio riceve in è Handler.

Ecco un semplice servizio di esempio che utilizza un'interfaccia Messenger:

Kotlin

/** Command to the service to display a message.  */
private const val MSG_SAY_HELLO = 1

class MessengerService : Service() {

    /**
     * Target we publish for clients to send messages to IncomingHandler.
     */
    private lateinit var mMessenger: Messenger

    /**
     * Handler of incoming messages from clients.
     */
    internal class IncomingHandler(
            context: Context,
            private val applicationContext: Context = context.applicationContext
    ) : Handler() {
        override fun handleMessage(msg: Message) {
            when (msg.what) {
                MSG_SAY_HELLO ->
                    Toast.makeText(applicationContext, "hello!", Toast.LENGTH_SHORT).show()
                else -> super.handleMessage(msg)
            }
        }
    }

    /**
     * When binding to the service, we return an interface to our messenger
     * for sending messages to the service.
     */
    override fun onBind(intent: Intent): IBinder? {
        Toast.makeText(applicationContext, "binding", Toast.LENGTH_SHORT).show()
        mMessenger = Messenger(IncomingHandler(this))
        return mMessenger.binder
    }
}

Java

public class MessengerService extends Service {
    /**
     * Command to the service to display a message.
     */
    static final int MSG_SAY_HELLO = 1;

    /**
     * Handler of incoming messages from clients.
     */
    static class IncomingHandler extends Handler {
        private Context applicationContext;

        IncomingHandler(Context context) {
            applicationContext = context.getApplicationContext();
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_SAY_HELLO:
                    Toast.makeText(applicationContext, "hello!", Toast.LENGTH_SHORT).show();
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    /**
     * Target we publish for clients to send messages to IncomingHandler.
     */
    Messenger mMessenger;

    /**
     * When binding to the service, we return an interface to our messenger
     * for sending messages to the service.
     */
    @Override
    public IBinder onBind(Intent intent) {
        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
        mMessenger = new Messenger(new IncomingHandler(this));
        return mMessenger.getBinder();
    }
}

Il metodo handleMessage() nel Handler è il luogo in cui il servizio riceve il Message in arrivo e decide cosa fare, in base al membro what.

Tutto ciò che un client deve fare è creare un Messenger basato su IBinder restituito dal servizio e inviare un messaggio utilizzando send(). Ad esempio, di seguito è riportata un'attività che collega e consegna il messaggio MSG_SAY_HELLO al servizio:

Kotlin

class ActivityMessenger : Activity() {
    /** Messenger for communicating with the service.  */
    private var mService: Messenger? = null

    /** Flag indicating whether we have called bind on the service.  */
    private var bound: Boolean = false

    /**
     * Class for interacting with the main interface of the service.
     */
    private val mConnection = object : ServiceConnection {

        override fun onServiceConnected(className: ComponentName, service: IBinder) {
            // This is called when the connection with the service has been
            // established, giving us the object we can use to
            // interact with the service.  We are communicating with the
            // service using a Messenger, so here we get a client-side
            // representation of that from the raw IBinder object.
            mService = Messenger(service)
            bound = true
        }

        override fun onServiceDisconnected(className: ComponentName) {
            // This is called when the connection with the service has been
            // unexpectedly disconnected—that is, its process crashed.
            mService = null
            bound = false
        }
    }

    fun sayHello(v: View) {
        if (!bound) return
        // Create and send a message to the service, using a supported 'what' value.
        val msg: Message = Message.obtain(null, MSG_SAY_HELLO, 0, 0)
        try {
            mService?.send(msg)
        } catch (e: RemoteException) {
            e.printStackTrace()
        }

    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)
    }

    override fun onStart() {
        super.onStart()
        // Bind to the service.
        Intent(this, MessengerService::class.java).also { intent ->
            bindService(intent, mConnection, Context.BIND_AUTO_CREATE)
        }
    }

    override fun onStop() {
        super.onStop()
        // Unbind from the service.
        if (bound) {
            unbindService(mConnection)
            bound = false
        }
    }
}

Java

public class ActivityMessenger extends Activity {
    /** Messenger for communicating with the service. */
    Messenger mService = null;

    /** Flag indicating whether we have called bind on the service. */
    boolean bound;

    /**
     * Class for interacting with the main interface of the service.
     */
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            // This is called when the connection with the service has been
            // established, giving us the object we can use to
            // interact with the service.  We are communicating with the
            // service using a Messenger, so here we get a client-side
            // representation of that from the raw IBinder object.
            mService = new Messenger(service);
            bound = true;
        }

        public void onServiceDisconnected(ComponentName className) {
            // This is called when the connection with the service has been
            // unexpectedly disconnected—that is, its process crashed.
            mService = null;
            bound = false;
        }
    };

    public void sayHello(View v) {
        if (!bound) return;
        // Create and send a message to the service, using a supported 'what' value.
        Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
        try {
            mService.send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    @Override
    protected void onStart() {
        super.onStart();
        // Bind to the service.
        bindService(new Intent(this, MessengerService.class), mConnection,
            Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // Unbind from the service.
        if (bound) {
            unbindService(mConnection);
            bound = false;
        }
    }
}

Questo esempio non mostra come il servizio può rispondere al client. Se desideri servizio per rispondere, devi anche creare un Messenger nel client. Quando il client riceve il callback onServiceConnected(), invia un Message al servizio che include Messenger del cliente nel parametro replyTo del metodo send().

È possibile vedere un esempio di come offrire messaggi bidirezionali in MessengerService.java (servizio) e Esempi di MessengerServiceActivities.java (client).

Associazione a un servizio

I componenti dell'applicazione (client) possono essere associati a un servizio chiamando bindService(). Android quindi chiama il metodo onBind() del servizio, che restituisce un IBinder per l'interazione con il servizio.

L'associazione è asincrona e bindService() restituisce immediatamente senza restituire IBinder in il cliente. Per ricevere IBinder, il cliente deve creare un di ServiceConnection e la passiamo a bindService(). ServiceConnection include un metodo di callback che chiamate di sistema per l'invio del IBinder.

Nota: solo le attività, i servizi e i fornitori di contenuti possono vincolare a un servizio: non puoi eseguire l'associazione a un servizio da un broadcast receiver.

Per eseguire l'associazione a un servizio dal tuo client, segui questi passaggi:

  1. Implementa ServiceConnection.

    L'implementazione deve sostituire due metodi di callback:

    onServiceConnected()
    Il sistema la chiama per consegnare il valore IBinder restituito da il metodo onBind() del servizio.
    onServiceDisconnected()
    Il sistema Android lo chiama quando la connessione al servizio è inaspettata persi, ad esempio quando il servizio ha un arresto anomalo o si interrompe. Non chiamato quando slega il client.
  2. Chiama bindService(), superando l'implementazione di ServiceConnection.

    Nota: se il metodo restituisce false, il valore non dispone di una connessione valida al servizio. Invece, chiama unbindService() nel tuo client. In caso contrario, il client mantiene il servizio quando è inattivo.

  3. Quando il sistema chiama il metodo di callback onServiceConnected(), puoi iniziare a effettuare chiamate al servizio, utilizzando i metodi definiti dall'interfaccia.
  4. Per disconnetterti dal servizio, chiama unbindService().

    Se il client è ancora associato a un servizio quando l'app lo elimina, determina lo slegamento del client. È consigliabile svincolare il cliente non appena viene eseguito a interagire con il servizio. Ciò consente di arrestare il servizio inattivo. Per ulteriori informazioni sulle tempistiche appropriate per vincolare e svincolare, consulta la sezione Note aggiuntive.

L'esempio seguente collega il client al servizio creato in precedenza estendere la classe Binder, quindi deve solo trasmettere il testo restituito IBinder alla classe LocalBinder e richiedi l'istanza LocalService:

Kotlin

var mService: LocalService

val mConnection = object : ServiceConnection {
    // Called when the connection with the service is established.
    override fun onServiceConnected(className: ComponentName, service: IBinder) {
        // Because we have bound to an explicit
        // service that is running in our own process, we can
        // cast its IBinder to a concrete class and directly access it.
        val binder = service as LocalService.LocalBinder
        mService = binder.getService()
        mBound = true
    }

    // Called when the connection with the service disconnects unexpectedly.
    override fun onServiceDisconnected(className: ComponentName) {
        Log.e(TAG, "onServiceDisconnected")
        mBound = false
    }
}

Java

LocalService mService;
private ServiceConnection mConnection = new ServiceConnection() {
    // Called when the connection with the service is established.
    public void onServiceConnected(ComponentName className, IBinder service) {
        // Because we have bound to an explicit
        // service that is running in our own process, we can
        // cast its IBinder to a concrete class and directly access it.
        LocalBinder binder = (LocalBinder) service;
        mService = binder.getService();
        mBound = true;
    }

    // Called when the connection with the service disconnects unexpectedly.
    public void onServiceDisconnected(ComponentName className) {
        Log.e(TAG, "onServiceDisconnected");
        mBound = false;
    }
};

Con questo ServiceConnection, il client può eseguire l'associazione a un servizio passando a bindService(), come mostrato nell'esempio seguente:

Kotlin

Intent(this, LocalService::class.java).also { intent ->
    bindService(intent, connection, Context.BIND_AUTO_CREATE)
}

Java

Intent intent = new Intent(this, LocalService.class);
bindService(intent, connection, Context.BIND_AUTO_CREATE);
  • Il primo parametro di bindService() è un Intent che nomina esplicitamente il servizio da associare.

    Attenzione:se utilizzi un intent per l'associazione a una Service, assicurati che la tua app sia sicura con un messaggio esplicita l'intento. L'utilizzo di un intent implicito per avviare un servizio è un rischio per la sicurezza perché non puoi sapere con certezza quale servizio risponda all'intento, e l'utente non può vedere quale servizio viene avviato. A partire da Android 5.0 (livello API 21), il sistema genera un'eccezione se chiami bindService() con un intento implicito.

  • Il secondo parametro è l'oggetto ServiceConnection.
  • Il terzo parametro è un flag che indica le opzioni per l'associazione, di solito BIND_AUTO_CREATE, per creare il servizio, se non lo è già vivo. Gli altri valori possibili sono BIND_DEBUG_UNBIND, BIND_NOT_FOREGROUND o 0 per nessuno.

Note aggiuntive

Di seguito sono riportate alcune note importanti sull'associazione a un servizio:

  • Trappola sempre DeadObjectException eccezioni, che vengono generate quando si interrompe la connessione. Questa è l'unica eccezione generata dai metodi remoti.
  • Gli oggetti vengono conteggiati nei processi.
  • In genere accoppi l'associazione e lo slegamento durante Abbinando i momenti di lancio e rimozione del ciclo di vita del cliente, come descritto nei i seguenti esempi:
    • Se devi interagire con il servizio solo quando la tua attività è visibile, esegui l'associazione durante onStart() e slegala durante onStop().
    • Se vuoi che la tua attività riceva risposte anche quando è interrotta nella sfondo, eseguire l'associazione durante onCreate() e slegare durante onDestroy(). Ricorda che ciò implica che l'attività deve utilizzare il servizio per tutta la durata dell'esecuzione, anche in background; pertanto, quando se il servizio si trova in un altro processo, ne aumenti il peso di essere terminati dal sistema.

    Nota: di solito non vincoli e svincoli durante le richiamate onResume() e onPause() dell'attività, perché questi callback vengono eseguiti ogni durante la transizione del ciclo di vita. Mantieni al minimo l'elaborazione che si verifica in queste transizioni.

    Inoltre, se più attività nella tua applicazione sono associate allo stesso servizio ed è presente transizione tra due di queste attività, il servizio potrebbe essere eliminato e ricreato come attività slega (durante la pausa) prima di quella successiva vincolata (durante la ripresa). Questa attività passa per come e varie attività coordinano i loro cicli di vita è descritto in Il ciclo di vita dell'attività.

Per altro codice campione che mostra come eseguire l'associazione a un servizio, consulta Classe RemoteService.java in ApiDemos.

Gestire il ciclo di vita di un servizio associato

Quando un servizio viene slegato da tutti i client, il sistema Android lo elimina. (a meno che non sia stato iniziato a utilizzare startService()). Non devi quindi gestire il ciclo di vita del tuo servizio un servizio puramente vincolato. Il sistema Android le gestisce per te in base se è associato a qualche client.

Tuttavia, se scegli di implementare il metodo di callback onStartCommand(), devi interrompere esplicitamente il servizio perché è ora considerato avviato. In questo caso, il servizio viene eseguito fino a quando si arresta con stopSelf() o un altro componente chiama stopService(), a prescindere dal fatto che sia associato a qualche clienti.

Inoltre, se il servizio viene avviato e accetta l'associazione, quando il sistema chiama il tuo metodo onUnbind(), se vuoi puoi restituire true se vuoi ricevere una chiamata a onRebind() la prossima volta che un client si associa al servizio. onRebind() restituisce void, ma il client riceve comunque IBinder nella sua Chiamata onServiceConnected(). La figura seguente illustra la logica di questo tipo di ciclo di vita.

Figura 1. Il ciclo di vita di un servizio avviato e consente anche l'associazione.

Per saperne di più sul ciclo di vita di un servizio avviato, consulta la Panoramica dei servizi.