Omówienie powiązanych usług

Powiązana usługa to serwer w interfejsie klient-serwer. Umożliwia komponentom takich jak działania powiązane z usługą, wysyłanie żądań, otrzymywanie odpowiedzi komunikacji międzyprocesowej (IPC). Powiązana usługa zwykle działa tylko wtedy, gdy obsługuje inną aplikacji i nie działa w tle w nieskończoność.

Ten dokument opisuje sposób tworzenia powiązanej usługi, w tym sposobów tworzenia powiązania. z innych komponentów aplikacji. Dodatkowe informacje na temat usług dostępnych w ogólne, takie jak sposób dostarczania powiadomień z usługi i konfigurowanie jej tak, aby działała na pierwszym planie, zapoznaj się z Omówienie usług.

Podstawy

Powiązana usługa to implementacja klasy Service, która umożliwia inne aplikacje łączą go z nim i wchodzą z nim w interakcję. Aby udostępnić powiązanie dla zaimplementujesz metodę wywołania zwrotnego onBind(). Ten zwraca obiekt IBinder, który definiuje interfejs programowania, których klienci mogą używać do interakcji z usługą.

Powiąż z uruchomioną usługą

Jak wspominaliśmy w sekcji Omówienie usług, możesz utworzyć usługę, która jest zarówno rozpoczęta, jak i powiązana. Oznacza to, że możesz rozpocząć usłudze, wywołując metodę startService(). Zapewnia to świadczenie usługi w nieskończoność. Możesz też pozwolić klientowi na powiązanie z usługą przez Dzwonię pod bindService().

Jeśli zezwolisz na uruchomienie i powiązanie usługi, po jej uruchomieniu system nie zniszczy usługi po usunięciu powiązania wszystkich klientów. Zamiast tego musisz: wyraźnie zatrzymaj usługę, wywołując metodę stopSelf() lub stopService().

Chociaż zazwyczaj implementujesz onBind() lub onStartCommand(), czasami jest niezbędne do implementować oba te typy. Na przykład w odtwarzaczu muzycznym może się przydać, by umożliwić działanie usługi, w nieskończoność, a także wiązania. W ten sposób działanie może uruchomić usługę w celu odtwarzania muzyka, która będzie odtwarzana nawet wtedy, gdy użytkownik wyjdzie z aplikacji. Następnie, gdy użytkownik wraca do aplikacji, działanie może zostać powiązane z usługą, aby odzyskać kontrolę nad odtwarzania.

Aby uzyskać więcej informacji o cyklu życia usługi podczas dodawania powiązania do uruchomionej usługi, zobacz sekcję Zarządzanie cyklem życia powiązanej usługi.

Klient tworzy powiązanie z usługą przez wywołanie bindService() W takim przypadku musi udostępniają implementację tagu ServiceConnection, który monitoruje połączenie z usługą. Wartość zwrócona dla bindService() wskazuje, czy czy istnieje żądana usługa oraz czy klient ma do niej dostęp.

Kiedy Android tworzy połączenie między klientem a usługą, dzwoni do: onServiceConnected()ServiceConnection. Metoda onServiceConnected() zawiera IBinder argumentu, którego klient używa następnie do komunikowania się z powiązaną usługą.

Z usługą możesz połączyć wielu klientów jednocześnie. Jednak system zapisuje w pamięci podręcznej kanał komunikacji usługi IBinder. Inaczej mówiąc, system wywołuje metodę onBind() usługi do wygenerowania IBinder tylko wtedy, gdy pierwszy klientów. System dostarcza następnie ten sam IBinder do: wszystkich dodatkowych klientów powiązanych z tą samą usługą, bez konieczności onBind().

Gdy ostatni klient usunie powiązanie z usługą, system zniszczy usługę, chyba że usługa została uruchomiona przy użyciu startService().

Najważniejszym elementem implementacji powiązanej usługi jest zdefiniowanie interfejsu którą zwraca metoda wywołania zwrotnego onBind(). Poniżej zawiera omówienie kilku sposobów definiowania Interfejs IBinder.

Utwórz powiązaną usługę

Podczas tworzenia usługi zapewniającej powiązanie musisz podać IBinder udostępnia interfejs programowania, za pomocą którego klienci mogą korzystać z usługi. OK można zdefiniować interfejs na 3 sposoby:

Rozszerzanie klasy Binder
Jeśli usługa jest prywatna dla Twojej aplikacji i działa w tym samym procesie jako klient, co jest typowe, utwórz interfejs, rozszerzając Binder zajęcia i zwrócenie jego instancji z onBind() Klient otrzymuje Binder i może go używać, aby uzyskać bezpośredni dostęp do metod publicznych dostępnych w Binder lub Service.

Jest to preferowana technika, gdy usługa jest jedynie robotem działającym w tle aplikacji. Jedynym przypadkiem użycia, w którym nie jest to preferowany sposób tworzenia interfejsu, jeśli z usługi korzystają inne aplikacje lub procesy.

Korzystanie z czatu
Jeśli interfejs ma działać w różnych procesach, możesz utworzyć interfejsu usługi za pomocą interfejsu Messenger. W ten sposób usługa określa obiekt Handler, który odpowiada na różne typy obiektów Message.

To urządzenie (Handler) jest podstawą elementu Messenger, który może następnie współdzielić IBinder z klientem, umożliwiając mu wysyłanie poleceń do usługi za pomocą obiektów Message. Dodatkowo klient może zdefiniować Messenger dzięki czemu usługa może wysyłać wiadomości.

To najprostszy sposób komunikacji międzyprocesowej (IPC), ponieważ Messenger umieszcza wszystkie żądania w jednym wątku, dzięki czemu nie musisz ich projektować i zapewniać bezpieczeństwo w wątkach.

Używanie AIDL
Android Interface Definition Language (AIDL) rozkłada obiekty na elementów podstawowych zrozumiałych dla systemu operacyjnego i łączy je w różnych procesach, aby działać. IPC. Poprzednia metoda, wykorzystująca Messenger, jest oparta na AIDL jako i jej bazowej struktury.

Jak wspomnieliśmy w poprzedniej sekcji, Messenger tworzy kolejkę wszystkich żądań klientów w 1 wątku, więc usługa otrzymuje żądania pojedynczo. Jeśli: jednak chcesz, aby Twoja usługa obsługiwała jednocześnie wiele żądań, możesz używać AIDL bezpośrednio. W tym przypadku usługa musi być zabezpieczona wątkami i obsługiwać wiele wątków.

Aby bezpośrednio korzystać z AIDL, w celu utworzenia pliku .aidl definiującego interfejs programowania. Narzędzia Android SDK używają aby wygenerować klasę abstrakcyjną, która implementuje interfejs i obsługuje protokół IPC, które można następnie rozszerzyć w ramach usługi.

Uwaga: w przypadku większości aplikacji AIDL nie jest najlepszym wyborem ponieważ może ona wymagać wielowątkowości oraz może być bardziej skomplikowana. Dlatego w tym dokumencie nie omówiono sposobu aby używać go w swojej usłudze. Jeśli na pewno potrzebujesz aby bezpośrednio korzystać z AIDL, zobacz AIDL dokument.

Rozszerzanie klasy Binder

Jeśli z usługi korzysta tylko aplikacja lokalna i nie musi tego robić współdziałają z różnymi procesami, możesz zaimplementować własną klasę Binder, która udostępnia klientowi bezpośrednie dostęp do publicznych metod w usłudze.

Uwaga: działa to tylko wtedy, gdy klient i usługa są w tym samym miejscu. aplikacji i procesu, co jest najczęstsze. Ta funkcja sprawdza się na przykład w przypadku muzyki musi powiązać działanie z własną usługą odtwarzającą muzykę w tle.

Ustawienia należy skonfigurować w następujący sposób:

  1. Utwórz w swojej usłudze instancję Binder, która: jedną z tych wartości:
    • Zawiera metody publiczne, które klient może wywołać.
    • Zwraca bieżącą instancję Service, która ma metody publiczne który może zadzwonić.
    • Zwraca instancję innej klasy hostowanej przez usługę przy użyciu metod publicznych który może zadzwonić.
  2. Zwraca tę instancję instancji Binder z metody wywołania zwrotnego onBind().
  3. W kliencie odbierz Binder z metody wywołania zwrotnego onServiceConnected() oraz za pomocą podanych metod wykonywać wywołania powiązanej usługi.

Uwaga: usługa i klient muszą być w tym samym miejscu tak aby klient mógł rzutować zwrócony obiekt i prawidłowo wywoływać jego interfejsy API. Usługa i klient również muszą przejść ten sam proces, ponieważ ta metoda nie zapewnia na łączenie procesów.

Oto przykładowa usługa, która zapewnia klientom dostęp do metod w usłudze za pomocą implementacja 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 udostępnia klientom metodę getService() pobierania: bieżącej instancji instancji LocalService. Umożliwia to klientom wywoływanie metod publicznych w posprzedażna. Klienty mogą na przykład wywoływać z usługi usługę getRandomNumber().

Oto działanie, które wiąże z usługą LocalService i wywołuje funkcję getRandomNumber() po kliknięciu przycisku:

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

Poprzedni przykład pokazuje, jak klient tworzy powiązanie z usługą za pomocą implementacji ServiceConnection i wywołanie zwrotne onServiceConnected(). Następny zawiera więcej informacji o procesie tworzenia powiązania z usługą.

Uwaga: w poprzednim przykładzie para klucz-wartość Metoda onStop() usuwa powiązanie klienta z usługą. Usuwanie powiązań klientów z usługami w odpowiednich momentach, jak omówiono w Dodatkowe uwagi.

Więcej przykładowego kodu znajdziesz tutaj: LocalService.java i LocalServiceActivities.java w ApiDemos.

Korzystanie z czatu

Jeśli Twoja usługa ma komunikować się z procesami zdalnymi, możesz użyć Messenger udostępnia interfejs Twojej usługi. Ta technika pozwala umożliwia korzystanie z komunikacji międzyprocesowej (IPC) bez konieczności korzystania z AIDL.

Korzystanie z interfejsu użytkownika Messenger jest łatwiejsze niż używanie AIDL, ponieważ kolejki: Messenger wszystkich wywołań usługi. Interfejs czysty AIDL wysyła równocześnie żądania do która musi obsługiwać wielowątkowość.

W większości aplikacji usługa nie musi obsługiwać wielowątkowości, więc użycie interfejsu Messenger pozwala usłudze obsługiwać tylko 1 wywołanie w danym momencie. Jeśli to ważne aby usługa była wielowątkowa, zdefiniuj interfejs za pomocą AIDL.

Podsumowanie korzystania z narzędzia Messenger:

  1. Usługa implementuje funkcję Handler, która otrzymuje wywołanie zwrotne dla każdego od klienta.
  2. Usługa używa Handler do utworzenia Messenger obiekt (który odwołuje się do Handler).
  3. Messenger tworzy IBinder, które usługa wraca do klientów z: onBind().
  4. Klienty używają interfejsu IBinder do tworzenia instancji Messenger (odwołuje się do pola Handler usługi), którego klient używa do wysyłania Obiekty usługi Message.
  5. Usługa odbiera każde Message w elemencie Handler, a konkretnie w metodzie handleMessage().

Dzięki temu nie ma żadnych metod, które klient mógłby wywołać usługę. Zamiast tego makro klient dostarcza wiadomości (obiekty: Message), które usługa otrzymuje w to Handler.

Oto prosta przykładowa usługa, która korzysta z interfejsu 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();
    }
}

Metoda handleMessage() w Handler to miejsce, w którym usługa odbiera przychodzące Message i decyduje, co zrobić, na podstawie informacji z grupy what.

Wystarczy, że klient utworzy Messenger na podstawie IBinder zwróconego przez usługę i wyśle wiadomość za pomocą send(). Oto na przykład działanie, które wiąże się z i dostarcza do niej komunikat MSG_SAY_HELLO:

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

Ten przykład nie pokazuje, jak usługa może odpowiedzieć klientowi. Jeśli chcesz, aby atrybut aby odpowiedzieć, musisz też utworzyć w kliencie Messenger. Gdy klient otrzyma wywołanie zwrotne onServiceConnected(), wysyła do usługi Message, która zawiera Messenger klienta w parametrze replyTo metody send().

Przykład dwukierunkowej komunikacji znajdziesz w MessengerService.java (usługa) i Przykłady: MessengerServiceActivities.java (klient).

Powiąż z usługą

Komponenty aplikacji (klienci) mogą powiązać z usługą za pomocą wywołania bindService() Android system następnie wywołuje metodę onBind() usługi, która zwraca IBinder w celu interakcji z i z usługami.

Powiązanie jest asynchroniczne i bindService() wraca natychmiast bez zwracania IBinder do klienta. Aby otrzymać IBinder, klient musi utworzyć wystąpienia ServiceConnection i przekazać je do bindService(). ServiceConnection zawiera metodę wywołania zwrotnego, która umożliwia aby uzyskać IBinder.

Uwaga: powiązania mogą dotyczyć tylko aktywności, usług i treści. z usługą – nie możesz utworzyć powiązania z usługą z odbiornika.

Aby utworzyć powiązanie z usługą z poziomu klienta, wykonaj te czynności:

  1. Wdróż ServiceConnection.

    Implementacja musi zastąpić 2 metody wywołania zwrotnego:

    onServiceConnected()
    System wywołuje tę funkcję, by dostarczyć IBinder zwrócony przez metody onBind() usługi.
    onServiceDisconnected()
    System Android wywołuje tę funkcję, gdy połączenie z usługą jest nieoczekiwanie nawiązywane np. gdy usługa ulegnie awarii lub zostanie zatrzymana. To nie gdy funkcja usunięcie powiązania klienta.
  2. Wywołaj bindService(), przekazując implementację ServiceConnection.

    Uwaga: jeśli metoda zwraca wartość Fałsz, Klient nie ma prawidłowego połączenia z usługą. Zadzwoń jednak unbindService() po stronie klienta. W przeciwnym razie klient uniemożliwi usługę zamykanie, gdy jest bezczynny.

  3. Gdy system wywoła metodę wywołania zwrotnego onServiceConnected(), możesz zacząć wywoływać usługę za pomocą metod określonych w interfejsie.
  4. Aby rozłączyć się z usługą, zadzwoń pod numer unbindService().

    Jeśli po zniszczeniu przez aplikację klient jest nadal powiązany z usługą, zniszczenie powoduje usunięcie powiązania klienta. Lepszym rozwiązaniem jest usuwanie powiązania klienta zaraz po zakończeniu tego procesu podczas interakcji z usługą. Spowoduje to wyłączenie nieaktywnej usługi. Więcej informacji na temat konfiguracji o tym, kiedy należy utworzyć powiązanie i usunąć powiązanie, zapoznaj się z sekcją Dodatkowe uwagi.

Poniższy przykład łączy klienta z usługą utworzoną wcześniej przez rozszerzanie klasy Binder, więc wystarczy rzutować zwrócona IBinder do klasy LocalBinder i poproś o instancję 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;
    }
};

Za pomocą ServiceConnection, klient może utworzyć powiązanie z usługą po zaliczeniu do bindService(), jak w tym przykładzie:

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);
  • Pierwszym parametrem zmiennej bindService() jest Intent wprost określa powiązanie usługi.

    Uwaga: jeśli zamierzasz użyć powiązania z Service, upewnij się, że Twoja aplikacja jest bezpieczna, używając dlatego intencji. Użycie intencji ogólnej do uruchomienia usługi zagraża bezpieczeństwu, ponieważ nie masz pewności, która usługa zareaguje na intencję, a użytkownik nie widzi, która usługa się uruchamia. Począwszy od Androida 5.0 (poziom interfejsu API 21), system zwróci wyjątek, jeśli wywołasz funkcję bindService() z intencją niejawną.

  • Drugim parametrem jest obiekt ServiceConnection.
  • Trzeci parametr to flaga wskazująca opcje powiązania – zwykle BIND_AUTO_CREATE – służąca do utworzenia usługi, jeśli jeszcze nie jest. żyje. Inne możliwe wartości to BIND_DEBUG_UNBIND, BIND_NOT_FOREGROUND lub 0 w przypadku braku.

Uwagi dodatkowe

Oto kilka ważnych uwag na temat powiązań z usługą:

  • Zawsze przechwytuj DeadObjectException wyjątków, które są zgłaszane gdy połączenie zostało przerwane. Jest to jedyny wyjątek zgłoszony przez metody zdalne.
  • Obiekty są wartościami referencyjnymi zliczonymi w procesach.
  • Powiązanie i usuwanie powiązania zazwyczaj są parowane podczas odpowiednich momentów w cyklu życia klienta, zgodnie z opisem w następujące przykłady:
    • Jeśli chcesz korzystać z usługi tylko wtedy, gdy Twoja aktywność jest widoczna, utwórz powiązanie podczas onStart() i usuń powiązanie podczas onStop().
    • Jeśli chcesz, aby Twoja aktywność otrzymywała odpowiedzi nawet po zatrzymaniu jej w w tle, utwórz powiązanie podczas onCreate() i usuń powiązanie w okresie onDestroy(). Pamiętaj, że oznacza to, że działanie musi korzystać z usługi przez cały czas działania, nawet w tle, więc gdy usługa jest w innym procesie, zwiększa się waga tego procesu, że system może go zabić.

    Uwaga: zazwyczaj nie tworzysz powiązań. w trakcie wywołań zwrotnych onResume() i onPause(), ponieważ te wywołania mają miejsce w każdym przejścia w cyklu życia usługi. Ogranicz do minimum czas przetwarzania w tych przejściach.

    Ponadto, jeśli wiele działań w aplikacji jest powiązanych z tą samą usługą i istnieje przejście między może dojść do zniszczenia usługi i utworzenia jej usunięcie powiązań aktywności (podczas pauzy) przed następnym powiązaniem (podczas wznawiania). Przejście aktywności polega na czynności koordynujące swoje cykle życia zostały opisane w artykule na temat cyklu życia aktywności.

Aby uzyskać więcej przykładowego kodu pokazującego, jak utworzyć powiązanie z usługą, zapoznaj się z RemoteService.java w ApiDemos.

Zarządzanie cyklem życia powiązanej usługi

Gdy usługa nie jest powiązana ze wszystkimi klientami, system Android ją zniszczy. (chyba że była używana funkcja startService()). Dzięki temu nie musisz zarządzać cyklem życia usługi, czysto powiązana usługa. System Android zarządza nim za Ciebie na podstawie niezależnie od tego, czy jest związana z klientami.

Jeśli jednak zdecydujesz się zaimplementować metodę wywołania zwrotnego onStartCommand(), musisz jawnie zatrzymać usługę, ponieważ usługa jest teraz uznawana za rozpoczętą. W takim przypadku usługa działa do momentu, gdy usługa zatrzymuje się wywołaniem stopSelf() lub innego komponentu stopService(), niezależnie od tego, czy jest powiązane z klientów.

Ponadto, jeśli usługa została uruchomiona i akceptuje wiązanie, to po wywołaniu systemu metody onUnbind(), możesz opcjonalnie zwrócić true, jeśli chcesz otrzymać połączenie z numerem onRebind(), gdy klient następnym razem połączy się z usługą. Metoda onRebind() zwraca nieważną wartość, ale klient nadal otrzymuje IBinder w onServiceConnected() oddzwonienie. Na ilustracji poniżej przedstawiono logikę tego rodzaju cyklu życia.

Rysunek 1. Cykl życia uruchomionej usługi a także powiązania.

Więcej informacji o cyklu życia uruchomionej usługi znajdziesz w artykule Omówienie usług.