Gebundene Dienste – Übersicht

Ein gebundener Dienst ist der Server in einer Client-Server-Schnittstelle. Damit können Komponenten z. B. Aktivitäten, die an den Dienst gebunden sind, Anfragen senden, Antworten empfangen und Interprocess Communication (IPC) Ein gebundener Dienst ist in der Regel nur verfügbar, während er einen anderen Dienst bedient. Anwendungskomponente und wird nicht unbegrenzt im Hintergrund ausgeführt.

In diesem Dokument wird beschrieben, wie Sie einen gebundenen Dienst erstellen und binden. von anderen Anwendungskomponenten zum Dienst. Weitere Informationen zu Diensten in allgemeine Informationen, z. B. wie Benachrichtigungen von einem Dienst zugestellt und der Dienst ausgeführt wird im Vordergrund finden Sie im Übersicht über die Dienste

Grundlagen

Ein gebundener Dienst ist eine Implementierung der Klasse Service, mit der sich andere Anwendungen sich an sie binden und mit ihr interagieren. Um eine Bindung für eine implementieren Sie die Callback-Methode onBind(). Dieses gibt ein IBinder-Objekt zurück, das die Programmierschnittstelle definiert, die über die Clients mit dem Dienst interagieren können.

An gestarteten Dienst binden

Wie in der Übersicht über die Dienste beschrieben, können Sie einen Dienst erstellen, der sowohl gestartet als auch gebunden ist. Das heißt, Sie können indem Sie startService() aufrufen. Dadurch kann der auf unbestimmte Zeit. Sie können auch zulassen, dass ein Client an den Dienst gebunden wird, indem Sie bindService() wird angerufen.

Wenn Sie Ihren Dienst starten und gebunden haben, Das System zerstört den Dienst nicht, wenn alle Clients die Bindung aufheben. Stattdessen müssen Sie beenden Sie den Dienst explizit durch Aufrufen von stopSelf() oder stopService().

Normalerweise implementieren Sie entweder onBind() oder onStartCommand() ist es manchmal notwendig, um um beide zu implementieren. Beispielsweise kann ein Musikplayer seinen Dienst und bindend. So kann der Dienst durch eine Aktivität gestartet werden, und die Musik wird weiter abgespielt, auch wenn der Nutzer die App verlässt. Wenn die Nutzenden an die Anwendung zurückgegeben wird, kann die Aktivität an den Dienst gebunden werden, um die Kontrolle über Wiedergabe starten.

Weitere Informationen zum Dienstlebenszyklus beim Hinzufügen einer Bindung zu einem gestarteten Dienst Weitere Informationen finden Sie im Abschnitt Lebenszyklus eines gebundenen Dienstes verwalten.

Ein Client bindet sich an einen Dienst, indem er Folgendes aufruft: bindService() Wenn dies der Fall ist, eine Implementierung von ServiceConnection bereitstellen, die überwacht die Verbindung mit dem Dienst. Der Rückgabewert von bindService() gibt an, ob der der angeforderte Dienst existiert und ob der Client Zugriff darauf hat.

Wann? stellt das Android-System die Verbindung zwischen Client und Dienst her. ruft onServiceConnected() an am ServiceConnection. Die Die Methode onServiceConnected() enthält ein IBinder. , das der Client dann für die Kommunikation mit dem gebundenen Dienst verwendet.

Sie können mehrere Clients gleichzeitig mit einem Dienst verbinden. Die Das System speichert den Kommunikationskanal des IBinder-Dienstes im Cache. Mit anderen Worten, das System ruft die onBind() des Dienstes auf , um die IBinder nur zu generieren, wenn die erste Clientbindungen. Das System liefert dieselben IBinder alle zusätzlichen Clients, die an denselben Dienst gebunden sind, ohne Noch einmal onBind().

Wenn der letzte Client die Bindung an den Dienst aufhebt, wird der Dienst vom System gelöscht, es sei denn, der Dienst wurde mit startService() gestartet.

Der wichtigste Teil der Implementierung eines gebundenen Dienstes ist das Definieren der Schnittstelle das die Callback-Methode onBind() zurückgibt. Die folgenden werden verschiedene Möglichkeiten erläutert, IBinder-Schnittstelle.

gebundenen Dienst erstellen

Wenn Sie einen Dienst erstellen, der eine Bindung bereitstellt, müssen Sie einen IBinder angeben , die die Programmierschnittstelle zur Verfügung stellt, über die Clients mit dem Dienst interagieren können. Es können Sie die Schnittstelle auf drei Arten definieren:

Binder-Klasse erweitern
Wenn Ihr Dienst privat ist und im selben Prozess ausgeführt wird als Client, was häufig verwendet wird, erstellen Sie Ihre Schnittstelle, indem Sie den Binder Klasse und eine Instanz davon onBind() Der Client empfängt die Binder und kann damit direkt auf öffentliche Methoden zugreifen, die entweder im Binder verfügbar sind oder der Service.

Dies ist die bevorzugte Methode, wenn Ihr Dienst nur ein Hintergrund-Worker ist . Der einzige Anwendungsfall, wenn dies nicht die bevorzugte Methode zum Erstellen Ihrer Schnittstelle ist, ist wenn Ihr Dienst von anderen Anwendungen oder in separaten Prozessen verwendet wird.

Messenger verwenden
Wenn Sie Ihre Oberfläche für verschiedene Prozesse benötigen, Schnittstelle für den Dienst mit einem Messenger. Auf diese Weise kann der Dienst definiert ein Handler, das auf verschiedene Typen von Message-Objekten reagiert.

Dieses Handler ist die Grundlage für ein Messenger, das dann ein IBinder teilen kann mit dem Client, damit dieser mithilfe von Message-Objekten Befehle an den Dienst senden kann. Außerdem kann der Client eine Messenger von damit der Dienst Nachrichten zurücksenden kann.

Dies ist die einfachste Methode, um eine Interprozesskommunikation (IPC) durchzuführen, da der Messenger alle Anfragen in einem einzigen Thread in die Warteschlange stellt. Thread-sicher zu machen.

AIDL verwenden
Android Interface Definition Language (AIDL) zerlegt Objekte in Primitiven, die das Betriebssystem verstehen kann, und verteilt sie zwischen Prozessen, IPC Das vorherige Verfahren, bei dem ein Messenger verwendet wird, basiert tatsächlich auf AIDL als zugrunde liegen.

Wie im vorherigen Abschnitt erwähnt, erstellt Messenger eine Warteschlange mit alle Clientanfragen in einem Thread enthalten, damit der Dienst eine Anfrage nach der anderen empfängt. Wenn: Wenn Ihr Dienst jedoch mehrere Anfragen gleichzeitig verarbeiten soll, können Sie AIDL verwenden. . In diesem Fall muss Ihr Dienst threadsicher und Multithreading-fähig sein.

Um AIDL direkt zu verwenden, eine .aidl-Datei erstellen, die die Programmierschnittstelle definiert. Die Android SDK-Tools nutzen diese Datei aus, um eine abstrakte Klasse zu generieren, die das -Interface implementiert und IPC verarbeitet. die innerhalb Ihres Dienstes erweitert werden können.

Hinweis:Für die meisten Anwendungen ist AIDL nicht die beste Wahl für einen gebundenen Dienst erstellen, da dies Multithreading-Funktionen und kann die Implementierung komplizierter gestalten. Daher wird in diesem Dokument nicht erläutert, wie um sie für Ihren Dienst zu nutzen. Wenn Sie sicher sind, dass Sie Wenn Sie AIDL direkt verwenden möchten, siehe AIDL Dokument.

Binder-Klasse erweitern

Wenn nur die lokale Anwendung Ihren Dienst verwendet und diese nicht prozessübergreifend arbeiten, Dann können Sie Ihre eigene Binder-Klasse implementieren, die Ihrem Client direkte Zugriffe bereitstellt. auf öffentliche Methoden im Dienst zugreifen können.

Hinweis:Dies funktioniert nur, wenn sich Client und Dienst im selben Anwendung und Prozess, was am häufigsten ist. Das eignet sich gut für eine Musik, -Anwendung, die eine Aktivität mit ihrem eigenen Dienst verknüpfen muss, der Musik im Hintergrund.

Und so funktioniert es:

  1. Erstellen Sie in Ihrem Dienst eine Instanz von Binder, die eines der folgenden: <ph type="x-smartling-placeholder">
      </ph>
    • Enthält öffentliche Methoden, die der Client aufrufen kann.
    • Gibt die aktuelle Service-Instanz zurück, die die öffentlichen Methoden der aufrufen kann.
    • Gibt eine Instanz einer anderen Klasse zurück, die vom Dienst mit öffentlichen Methoden gehostet wird aufrufen kann.
  2. Gibt diese Instanz von Binder von der Callback-Methode onBind() zurück.
  3. Empfangen Sie im Client die Binder von der Callback-Methode onServiceConnected() und den gebundenen Dienst mit den bereitgestellten Methoden aufrufen.

Hinweis:Dienst und Client müssen sich im selben , damit der Client das zurückgegebene Objekt umwandeln und seine APIs ordnungsgemäß aufrufen kann. Dienst und der Kunde müssen sich im selben Prozess befinden. Marshalling zwischen Prozessen.

Hier sehen Sie als Beispiel einen Dienst, der Clients Zugriff auf Methoden im Dienst über eine Binder-Implementierung:

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 stellt die getService()-Methode für Clients zum Abrufen von aktuelle Instanz von LocalService. Dadurch können Clients öffentliche Methoden in der . Clients können beispielsweise getRandomNumber() über den Dienst aufrufen.

Hier ist eine Aktivität, die eine Bindung an LocalService herstellt und getRandomNumber() aufruft wenn auf eine Schaltfläche geklickt wird:

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;
        }
    };
}

Das vorherige Beispiel zeigt, wie sich der Client mithilfe einer Implementierung von ServiceConnection und der Callback onServiceConnected(). Die nächste enthält weitere Informationen zu diesem Vorgang der Bindung an den Dienst.

Hinweis:Im vorherigen Beispiel hat der Parameter Die Methode onStop() hebt die Bindung des Clients an den Dienst auf. Heben Sie die Bindung von Clients an Dienste zu geeigneten Zeiten auf, wie in den Zusätzliche Hinweise.

Weiteren Beispielcode finden Sie in der LocalService.java-Klasse und die LocalServiceActivities.java in ApiDemos.

Messenger verwenden

Wenn Ihr Dienst mit Remote-Prozessen kommunizieren soll, können Sie einen Messenger, um die Schnittstelle für Ihren Dienst bereitzustellen. Mit dieser Technik können Sie führen Interprocess Communication (IPC) durch, ohne AIDL verwenden zu müssen.

Die Verwendung von Messenger für Ihre Schnittstelle einfacher als AIDL, da Messenger-Warteschlangen an den Dienst senden. Eine reine AIDL-Schnittstelle sendet gleichzeitige Anfragen an den der dann Multithreading verarbeiten muss.

Bei den meisten Anwendungen muss der Dienst kein Multithreading ausführen, sodass der Dienst mit einem Messenger jeweils nur einen Aufruf verarbeiten kann. Wenn es wichtig ist, Wenn Ihr Dienst Multithreaded sein soll, verwenden Sie AIDL, um Ihre Schnittstelle zu definieren.

Hier ist eine Zusammenfassung der Verwendung von Messenger:

  1. Der Dienst implementiert eine Handler, die für jedes Anruf von einem Kunden.
  2. Der Dienst verwendet den Handler, um einen Messenger zu erstellen Objekt Dies ist ein Verweis auf Handler.
  3. Der Messenger erstellt ein IBinder, das vom Dienst geht von onBind() an Kunden zurück.
  4. Clients verwenden die IBinder, um die Messenger zu instanziieren (die auf die Handler des Dienstes verweist), die der Client zum Senden Message-Objekte für den Dienst.
  5. Der Dienst empfängt jede Message in seiner Handler, genauer gesagt in der handleMessage()-Methode.

Auf diese Weise gibt es keine Methoden, die der Client für den Dienst aufrufen kann. Stattdessen Der Client stellt Nachrichten (Message-Objekte) zu, die vom Dienst erhält in Das ist Handler.

Hier ist ein einfacher Beispieldienst, der eine Messenger-Schnittstelle verwendet:

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();
    }
}

Die Methode handleMessage() in der Handler ist der Ort, an dem der Dienst die eingehenden Message empfängt. und entscheidet anhand des what-Mitglieds, was zu tun ist.

Ein Client muss lediglich eine Messenger auf Basis der vom Dienst zurückgegebenen IBinder erstellen und eine Nachricht mit send() senden. Hier sehen Sie als Beispiel eine Aktivität, die an die -Dienst und stellt die MSG_SAY_HELLO-Nachricht an den Dienst zu:

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&mdash;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&mdash;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;
        }
    }
}

Dieses Beispiel zeigt nicht, wie der Dienst dem Client antworten kann. Wenn Sie möchten, dass die um zu antworten, müssen Sie auch eine Messenger im Client erstellen. Wenn der Client den onServiceConnected()-Callback empfängt, wird eine Message an den Dienst gesendet, die Folgendes beinhaltet: Messenger des Clients im Parameter replyTo der Methode send().

Ein Beispiel für die bidirektionale Benachrichtigung findest du im MessengerService.java (Dienst) und MessengerServiceActivities.java-Beispiele (Client).

An einen Dienst binden

Anwendungskomponenten (Clients) können durch Aufrufen von bindService() Das Android- ruft das System die Methode onBind() des Dienstes auf, die ein IBinder für die Interaktion mit für den Dienst.

Die Bindung ist asynchron und bindService() gibt sofort zurück, ohne IBinder an Kundschaft. Um die IBinder zu erhalten, muss der Client ein Instanz von ServiceConnection und übergeben Sie sie an bindService(). ServiceConnection enthält eine Callback-Methode, mit der die Systemaufrufe zur Übermittlung von IBinder.

Hinweis:Nur Aktivitäten, Dienste und Contentanbieter können verbindliche zu einem Dienst. Eine Bindung an einen Dienst von einem Übertragungsempfänger ist nicht möglich.

So binden Sie Ihren Client an einen Dienst:

  1. Implementieren Sie ServiceConnection.

    Ihre Implementierung muss zwei Callback-Methoden überschreiben:

    onServiceConnected()
    Das System ruft dies auf, um die vom System zurückgegebenen IBinder zu senden. mit der Methode onBind() des Dienstes.
    onServiceDisconnected()
    Das Android-System ruft diese Nachricht auf, wenn die Verbindung zum Dienst unerwartet ist zum Beispiel, wenn der Dienst abstürzt oder beendet wird. Dies ist nicht aufgerufen, wenn der hebt die Bindungen auf.
  2. Rufen Sie bindService() auf und übergeben Sie die ServiceConnection-Implementierung.

    Hinweis:Wenn die Methode „false“ zurückgibt, Client hat keine gültige Verbindung zum Dienst. Rufen Sie jedoch unbindService() in Ihrem Auftraggebenden. Andernfalls unterbindet Ihr Client den Dienst im Leerlauf heruntergefahren.

  3. Wenn das System Ihre onServiceConnected()-Callback-Methode aufruft, können Sie Aufrufe an den Dienst senden, indem Sie die von der Schnittstelle definierten Methoden.
  4. Rufen Sie unbindService() auf, um die Verbindung zum Dienst zu trennen.

    Wenn Ihr Client immer noch an einen Dienst gebunden ist, während Ihre Anwendung den Client löscht, werden die Daten gelöscht führt dazu, dass der Client die Bindung aufhebt. Es empfiehlt sich, die Bindung des Clients sofort nach Abschluss des Vorgangs aufzuheben mit dem Dienst interagieren. Dadurch kann der inaktive Dienst heruntergefahren werden. Weitere Informationen Informationen zu geeigneten Zeitpunkten zum Binden und Aufheben der Bindung finden Sie im Abschnitt Zusätzliche Hinweise.

Im folgenden Beispiel wird der Client mit dem zuvor durch Erweitern der Binder-Klasse, sodass Sie nur die zurückgegebene IBinder an die Klasse LocalBinder und fordern Sie die Instanz LocalService an:

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;
    }
};

Mit diesem ServiceConnection kann sich der Client an einen Dienst binden indem Sie es an bindService(), wie im folgenden Beispiel gezeigt:

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);
  • Der erste Parameter von bindService() ist ein Intent, die den zu bindenden Dienst explizit benennen.

    Achtung:Wenn Sie einen Intent zur Bindung an einen Service, achte darauf, dass deine App sicher ist, indem du ein explizites die Nutzerabsicht verstehen. Die Verwendung eines impliziten Intents zum Starten eines Dienstes Sicherheitsrisiko, da Sie nicht sicher sind, welcher Dienst auf den Intent reagiert, und der Nutzer kann nicht sehen, welcher Dienst gestartet wird. Ab Android 5.0 (API-Level 21) das System löst eine Ausnahme aus, wenn Sie bindService() aufrufen mit einer impliziten Absicht.

  • Der zweite Parameter ist das Objekt ServiceConnection.
  • Der dritte Parameter ist ein Flag, das Optionen für die Bindung angibt – normalerweise BIND_AUTO_CREATE, um den Dienst zu erstellen, falls noch nicht geschehen. zum Leben erweckt wird. Andere mögliche Werte sind BIND_DEBUG_UNBIND, BIND_NOT_FOREGROUND oder 0 für keine.

Zusätzliche Anmerkungen

Hier sind einige wichtige Hinweise zur Bindung an einen Dienst:

  • DeadObjectException-Ausnahmen immer erfassen, die ausgelöst werden wenn die Verbindung unterbrochen wird. Dies ist die einzige Ausnahme, die von Remote-Methoden ausgelöst wird.
  • Objekte werden prozessübergreifend gezählt.
  • Normalerweise koppeln Sie das Binden und das Aufheben der Bindung während der Abgleichen der Zeitpunkte des Hochfahrens und Entfernens von Daten im Lebenszyklus des Kunden, wie in den folgende Beispiele: <ph type="x-smartling-placeholder">
      </ph>
    • Wenn Sie nur mit dem Dienst interagieren müssen, während Ihre Aktivität sichtbar ist, binden Sie die Bindung während onStart() und heben Sie die Bindung während onStop() auf.
    • Wenn Sie möchten, dass Ihre Aktivität auch dann Antworten erhält, wenn sie im Hintergrund, während onCreate() binden und Bindung aufheben im onDestroy(). Beachten Sie, dass dies impliziert, muss der Dienst während seiner gesamten Ausführung – auch im Hintergrund – genutzt werden. sich der Dienst in einem anderen Prozess befindet, steigern Sie das Gewicht des Prozesses dass sie vom System abgerissen werden.

    Hinweis:Normalerweise wird das Binden nicht angewendet und die Bindung wird aufgehoben. während der onResume()- und onPause()-Callbacks deiner Aktivität, da diese Callbacks an jedem Tag Lebenszykluswechsel. Begrenzen Sie die Verarbeitung an diesen Übergängen auf ein Minimum.

    Wenn außerdem mehrere Aktivitäten in Ihrer Anwendung an denselben Dienst gebunden sind und es eine Übergang zwischen könnte der Dienst zerstört und als aktueller Dienst neu erstellt werden, Bindungen von Aktivitäten aufheben (während der Pause) vor der nächsten Bindung (während des Fortfahrens). Bei diesem Aktivitätswechsel Informationen zur Koordinierung ihres Lebenszyklus durch Aktivitäten finden Sie unter Aktivitätslebenszyklus.

Weiteren Beispielcode, der die Bindung an einen Dienst zeigt, finden Sie in der RemoteService.java in ApiDemos.

Lebenszyklus eines gebundenen Dienstes verwalten

Wenn ein Dienst von allen Clients getrennt wird, wird er vom Android-System gelöscht (es sei denn, es wurde mit startService(). Sie müssen den Lebenszyklus Ihres Dienstes also nicht verwalten, ein gebundener Dienst. Das Android-System verwaltet dies für Sie basierend auf unabhängig davon, ob sie an Clients gebunden ist.

Wenn Sie sich jedoch dafür entscheiden, die Callback-Methode onStartCommand() zu implementieren, müssen Sie den Dienst ausdrücklich beenden, da das Ereignis Der Dienst gilt jetzt als gestartet. In diesem Fall wird der Dienst ausgeführt, bis der Dienst stoppt sich selbst mit stopSelf() oder eine andere Komponente ruft stopService() auf, unabhängig davon, ob sie an irgendwelche Kundschaft.

Wenn Ihr Dienst gestartet wird und Bindung akzeptiert, geschieht außerdem, wenn das System beim Aufruf von onUnbind()-Methode festlegen, können Sie optional true, wenn Sie einen Aufruf von onRebind() erhalten möchten, wenn das nächste Mal ein Client eine Bindung an den Dienst herstellt. onRebind() gibt eine ungültige Antwort zurück, aber der Kunde erhält das IBinder-Objekt trotzdem mit seiner onServiceConnected()-Callback. Die folgende Abbildung veranschaulicht die Logik für diese Art von Lebenszyklus.

Abbildung 1: Der Lebenszyklus eines gestarteten Dienstes und ermöglicht Bindungen.

Weitere Informationen zum Lebenszyklus eines gestarteten Dienstes finden Sie in der Dienstübersicht.