4.2.0.1 Android四大組件之- 綁定Service

綁定服務(wù):

綁定服務(wù)是客戶(hù)端-服務(wù)器接口中的服務(wù)器吮廉。綁定服務(wù)可讓組件(例如 Activity)綁定到服務(wù)递惋、發(fā)送請(qǐng)求、接收響應(yīng)佑惠,甚至執(zhí)行進(jìn)程間通信 (IPC)朋腋。 綁定服務(wù)通常只在為其他應(yīng)用組件服務(wù)時(shí)處于活動(dòng)狀態(tài),不會(huì)無(wú)限期在后臺(tái)運(yùn)行膜楷。

本文向您介紹如何創(chuàng)建綁定服務(wù)旭咽,包括如何綁定到來(lái)自其他應(yīng)用組件的服務(wù)。 不過(guò)赌厅,您還應(yīng)參閱服務(wù)文檔穷绵,了解有關(guān)一般服務(wù)的更多信息,例如:如何利用服務(wù)傳送通知特愿、如何將服務(wù)設(shè)置為在前臺(tái)運(yùn)行等等仲墨。

基礎(chǔ)知識(shí)


綁定服務(wù)是 Service類(lèi)的實(shí)現(xiàn),可讓其他應(yīng)用與其綁定和交互揍障。要提供服務(wù)綁定目养,您必須實(shí)現(xiàn) onBind()回調(diào)方法。該方法返回的 IBinder對(duì)象定義了客戶(hù)端用來(lái)與服務(wù)進(jìn)行交互的編程接口毒嫡。

客戶(hù)端可通過(guò)調(diào)用 [bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int))綁定到服務(wù)癌蚁。調(diào)用時(shí),它必須提供 ServiceConnection的實(shí)現(xiàn)兜畸,后者會(huì)監(jiān)控與服務(wù)的連接努释。[bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int))方法會(huì)立即無(wú)值返回,但當(dāng) Android 系統(tǒng)創(chuàng)建客戶(hù)端與服務(wù)之間的連接時(shí)膳叨,會(huì)調(diào)用 ServiceConnection上的 [onServiceConnected()](http://developer.android.com/reference/android/content/ServiceConnection.html#onServiceConnected(android.content.ComponentName, android.os.IBinder))洽洁,向客戶(hù)端傳遞用來(lái)與服務(wù)通信的IBinder

多個(gè)客戶(hù)端可同時(shí)連接到一個(gè)服務(wù)菲嘴。不過(guò)饿自,只有在第一個(gè)客戶(hù)端綁定時(shí),系統(tǒng)才會(huì)調(diào)用服務(wù)的 onBind()方法來(lái)檢索 IBinder龄坪。系統(tǒng)隨后無(wú)需再次調(diào)用 onBind()昭雌,便可將同一 IBinder傳遞至任何其他綁定的客戶(hù)端。

當(dāng)最后一個(gè)客戶(hù)端取消與服務(wù)的綁定時(shí)健田,系統(tǒng)會(huì)將服務(wù)銷(xiāo)毀(除非startService()也啟動(dòng)了該服務(wù))烛卧。

當(dāng)您實(shí)現(xiàn)綁定服務(wù)時(shí),最重要的環(huán)節(jié)是定義您的 onBind()回調(diào)方法返回的接口。您可以通過(guò)幾種不同的方法定義服務(wù)的IBinder接口总放,下文對(duì)這些方法逐一做了闡述呈宇。

綁定到已啟動(dòng)服務(wù)

正如服務(wù)文檔中所述,您可以創(chuàng)建同時(shí)具有已啟動(dòng)和綁定兩種狀態(tài)的服務(wù)局雄。 也就是說(shuō)甥啄,可通過(guò)調(diào)用startService()啟動(dòng)該服務(wù),讓服務(wù)無(wú)限期運(yùn)行炬搭;此外蜈漓,還可通過(guò)調(diào)用[bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int))使客戶(hù)端綁定到服務(wù)。

如果您確實(shí)允許服務(wù)同時(shí)具有已啟動(dòng)和綁定狀態(tài)宫盔,則服務(wù)啟動(dòng)后融虽,系統(tǒng)“絕對(duì)不會(huì)”在所有客戶(hù)端都取消綁定時(shí)銷(xiāo)毀服務(wù)。 為此灼芭,您必須通過(guò)調(diào)用[stopSelf()](http://developer.android.com/reference/android/app/Service.html#stopSelf()stopService()顯式停止服務(wù)有额。

盡管您通常應(yīng)該實(shí)現(xiàn) onBind()[onStartCommand()](http://developer.android.com/reference/android/app/Service.html#onStartCommand(android.content.Intent, int, int)),但有時(shí)需要同時(shí)實(shí)現(xiàn)這兩者姿鸿。例如谆吴,音樂(lè)播放器可能發(fā)現(xiàn)讓其服務(wù)無(wú)限期運(yùn)行并同時(shí)提供綁定很有用處。 這樣一來(lái)苛预,Activity 便可啟動(dòng)服務(wù)進(jìn)行音樂(lè)播放,即使用戶(hù)離開(kāi)應(yīng)用笋熬,音樂(lè)播放也不會(huì)停止热某。 然后,當(dāng)用戶(hù)返回應(yīng)用時(shí)胳螟,Activity 可綁定到服務(wù)昔馋,重新獲得回放控制權(quán)。

請(qǐng)務(wù)必閱讀管理綁定服務(wù)的生命周期部分糖耸,詳細(xì)了解有關(guān)添加綁定已啟動(dòng)服務(wù)時(shí)該服務(wù)的生命周期信息秘遏。

創(chuàng)建綁定服務(wù)


創(chuàng)建提供綁定的服務(wù)時(shí),您必須提供 IBinder嘉竟,用以提供客戶(hù)端用來(lái)與服務(wù)進(jìn)行交互的編程接口邦危。

您可以通過(guò)三種方法定義接口:

  • 擴(kuò)展 Binder 類(lèi)
    如果服務(wù)是供您的自有應(yīng)用專(zhuān)用,并且在與客戶(hù)端相同的進(jìn)程中運(yùn)行(常見(jiàn)情況)舍扰,則應(yīng)通過(guò)擴(kuò)展 Binder類(lèi)并從onBind()返回它的一個(gè)實(shí)例來(lái)創(chuàng)建接口倦蚪。客戶(hù)端收到Binder后边苹,可利用它直接訪(fǎng)問(wèn) Binder實(shí)現(xiàn)中乃至Service中可用的公共方法陵且。
    如果服務(wù)只是您的自有應(yīng)用的后臺(tái)工作線(xiàn)程,則優(yōu)先采用這種方法个束。 不以這種方式創(chuàng)建接口的唯一原因是慕购,您的服務(wù)被其他應(yīng)用或不同的進(jìn)程占用聊疲。

  • 使用 Messenger
    如需讓接口跨不同的進(jìn)程工作,則可使用 Messenger為服務(wù)創(chuàng)建接口沪悲。服務(wù)可以這種方式定義對(duì)應(yīng)于不同類(lèi)型 Message對(duì)象的 Handler售睹。此 HandlerMessenger的基礎(chǔ),后者隨后可與客戶(hù)端分享一個(gè) IBinder可训,從而讓客戶(hù)端能利用 Message對(duì)象向服務(wù)發(fā)送命令昌妹。此外,客戶(hù)端還可定義自有Messenger握截,以便服務(wù)回傳消息飞崖。
    這是執(zhí)行進(jìn)程間通信 (IPC) 的最簡(jiǎn)單方法,因?yàn)?Messenger會(huì)在單一線(xiàn)程中創(chuàng)建包含所有請(qǐng)求的隊(duì)列谨胞,這樣您就不必對(duì)服務(wù)進(jìn)行線(xiàn)程安全設(shè)計(jì)固歪。

  • 使用 AIDL
    AIDL(Android 接口定義語(yǔ)言)執(zhí)行所有將對(duì)象分解成原語(yǔ)的工作,操作系統(tǒng)可以識(shí)別這些原語(yǔ)并將它們編組到各進(jìn)程中胯努,以執(zhí)行 IPC牢裳。之前采用 Messenger的方法實(shí)際上是以 AIDL 作為其底層結(jié)構(gòu)。如上所述叶沛,Messenger會(huì)在單一線(xiàn)程中創(chuàng)建包含所有客戶(hù)端請(qǐng)求的隊(duì)列蒲讯,以便服務(wù)一次接收一個(gè)請(qǐng)求。不過(guò)灰署,如果您想讓服務(wù)同時(shí)處理多個(gè)請(qǐng)求判帮,則可直接使用 AIDL。 在此情況下溉箕,您的服務(wù)必須具備多線(xiàn)程處理能力晦墙,并采用線(xiàn)程安全式設(shè)計(jì)。
    如需直接使用 AIDL肴茄,您必須創(chuàng)建一個(gè)定義編程接口的 .aidl文件晌畅。Android SDK 工具利用該文件生成一個(gè)實(shí)現(xiàn)接口并處理 IPC 的抽象類(lèi),您隨后可在服務(wù)內(nèi)對(duì)其進(jìn)行擴(kuò)展寡痰。

注:大多數(shù)應(yīng)用“都不會(huì)”****使用 AIDL 來(lái)創(chuàng)建綁定服務(wù)抗楔,因?yàn)樗赡芤缶邆涠嗑€(xiàn)程處理能力,并可能導(dǎo)致實(shí)現(xiàn)的復(fù)雜性增加氓癌。因此谓谦,AIDL 并不適合大多數(shù)應(yīng)用,本文也不會(huì)闡述如何將其用于您的服務(wù)贪婉。如果您確定自己需要直接使用 AIDL反粥,請(qǐng)參閱 AIDL 文檔。

擴(kuò)展 Binder 類(lèi)

如果您的服務(wù)僅供本地應(yīng)用使用,不需要跨進(jìn)程工作才顿,則可以實(shí)現(xiàn)自有 Binder類(lèi)莫湘,讓您的客戶(hù)端通過(guò)該類(lèi)直接訪(fǎng)問(wèn)服務(wù)中的公共方法。

注:此方法只有在客戶(hù)端和服務(wù)位于同一應(yīng)用和進(jìn)程內(nèi)這一最常見(jiàn)的情況下方才有效郑气。 例如幅垮,對(duì)于需要將 Activity 綁定到在后臺(tái)播放音樂(lè)的自有服務(wù)的音樂(lè)應(yīng)用,此方法非常有效尾组。

以下是具體的設(shè)置方法:

  1. 在您的服務(wù)中忙芒,創(chuàng)建一個(gè)可滿(mǎn)足下列任一要求的 Binder實(shí)例:
  • 包含客戶(hù)端可調(diào)用的公共方法
  • 返回當(dāng)前 Service 實(shí)例,其中包含客戶(hù)端可調(diào)用的公共方法
  • 或返回由服務(wù)承載的其他類(lèi)的實(shí)例讳侨,其中包含客戶(hù)端可調(diào)用的公共方法
  1. onBind()回調(diào)方法返回此 Binder實(shí)例呵萨。
  2. 在客戶(hù)端中,從 [onServiceConnected()](http://developer.android.com/reference/android/content/ServiceConnection.html#onServiceConnected(android.content.ComponentName, android.os.IBinder))回調(diào)方法接收 Binder跨跨,并使用提供的方法調(diào)用綁定服務(wù)潮峦。

注:之所以要求服務(wù)和客戶(hù)端必須在同一應(yīng)用內(nèi),是為了便于客戶(hù)端轉(zhuǎn)換返回的對(duì)象和正確調(diào)用其 API勇婴。服務(wù)和客戶(hù)端還必須在同一進(jìn)程內(nèi)忱嘹,因?yàn)榇朔椒ú粓?zhí)行任何跨進(jìn)程編組。

例如耕渴,以下這個(gè)服務(wù)可讓客戶(hù)端通過(guò) Binder實(shí)現(xiàn)訪(fǎng)問(wèn)服務(wù)中的方法:

public class LocalService extends Service {
    // Binder given to clients
    private final IBinder mBinder = 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 mBinder;
    }

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

LocalBinder為客戶(hù)端提供 getService()方法拘悦,以檢索 LocalService的當(dāng)前實(shí)例。這樣萨螺,客戶(hù)端便可調(diào)用服務(wù)中的公共方法窄做。 例如,客戶(hù)端可調(diào)用服務(wù)中的 getRandomNumber()慰技。

點(diǎn)擊按鈕時(shí),以下這個(gè) Activity 會(huì)綁定到 LocalService并調(diào)用 getRandomNumber():

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, mConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // Unbind from the service
        if (mBound) {
            unbindService(mConnection);
            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 were something that might hang, then this request should
            // occur 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 mConnection = 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;
        }
    };
}

上例說(shuō)明了客戶(hù)端如何使用 ServiceConnection的實(shí)現(xiàn)和 [onServiceConnected()](http://developer.android.com/reference/android/content/ServiceConnection.html#onServiceConnected(android.content.ComponentName, android.os.IBinder))回調(diào)綁定到服務(wù)组砚。下文更詳細(xì)介紹了綁定到服務(wù)的過(guò)程吻商。

注:上例并未顯式取消與服務(wù)的綁定,但所有客戶(hù)端都應(yīng)在適當(dāng)?shù)臅r(shí)間(例如當(dāng) Activity 暫停時(shí))取消綁定糟红。

如需查看更多示例代碼艾帐,請(qǐng)參閱 ApiDemos 中的 LocalService.java
類(lèi)和 LocalServiceActivities.java
類(lèi)。

使用 Messenger

如需讓服務(wù)與遠(yuǎn)程進(jìn)程通信盆偿,則可使用 Messenger為您的服務(wù)提供接口柒爸。利用此方法,您無(wú)需使用 AIDL 便可執(zhí)行進(jìn)程間通信 (IPC)事扭。

當(dāng)您需要執(zhí)行 IPC 時(shí)捎稚,為您的接口使用Messenger要比使用 AIDL 實(shí)現(xiàn)它更加簡(jiǎn)單,因?yàn)?Messenger會(huì)將所有服務(wù)調(diào)用排入隊(duì)列,而純粹的 AIDL 接口會(huì)同時(shí)向服務(wù)發(fā)送多個(gè)請(qǐng)求今野,服務(wù)隨后必須應(yīng)對(duì)多線(xiàn)程處理葡公。
對(duì)于大多數(shù)應(yīng)用,服務(wù)不需要執(zhí)行多線(xiàn)程處理条霜,因此使用 Messenger可讓服務(wù)一次處理一個(gè)調(diào)用催什。如果您的服務(wù)必須執(zhí)行多線(xiàn)程處理,則應(yīng)使用 AIDL來(lái)定義接口宰睡。

以下是 Messenger 的使用方法摘要:

  • 服務(wù)實(shí)現(xiàn)一個(gè) Handler蒲凶,由其接收來(lái)自客戶(hù)端的每個(gè)調(diào)用的回調(diào)
  • Handler 用于創(chuàng)建 Messenger 對(duì)象(對(duì) Handler 的引用)
  • Messenger 創(chuàng)建一個(gè) IBinder,服務(wù)通過(guò) onBind() 使其返回客戶(hù)端
  • 客戶(hù)端使用 IBinder 將 Messenger(引用服務(wù)的 Handler)實(shí)例化拆内,然后使用后者將 Message 對(duì)象發(fā)送給服務(wù)
  • 服務(wù)在其 Handler 中(具體地講旋圆,是在 handleMessage() 方法中)接收每個(gè) Message

這樣,客戶(hù)端并沒(méi)有調(diào)用服務(wù)的“方法”矛纹。而客戶(hù)端傳遞的“消息”(Message對(duì)象)是服務(wù)在其 Handler
中接收的臂聋。

以下是一個(gè)使用 Messenger接口的簡(jiǎn)單服務(wù)示例:

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.
     */
    class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_SAY_HELLO:
                    Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    /**
     * Target we publish for clients to send messages to IncomingHandler.
     */
    final Messenger mMessenger = new Messenger(new IncomingHandler());

    /**
     * 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();
        return mMessenger.getBinder();
    }
}

請(qǐng)注意,服務(wù)就是在 HandlerhandleMessage()方法中接收傳入的 Message或南,并根據(jù) what成員決定下一步操作孩等。

客戶(hù)端只需根據(jù)服務(wù)返回的 IBinder創(chuàng)建一個(gè) Messenger,然后利用 send()發(fā)送一條消息采够。例如肄方,以下就是一個(gè)綁定到服務(wù)并向服務(wù)傳遞 MSG_SAY_HELLO消息的簡(jiǎn)單 Activity:

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

    /**
     * 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);
            mBound = 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;
            mBound = false;
        }
    };

    public void sayHello(View v) {
        if (!mBound) 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 (mBound) {
            unbindService(mConnection);
            mBound = false;
        }
    }
}

請(qǐng)注意,此示例并未說(shuō)明服務(wù)如何對(duì)客戶(hù)端作出響應(yīng)蹬癌。如果您想讓服務(wù)作出響應(yīng)权她,則還需要在客戶(hù)端中創(chuàng)建一個(gè)Messenger。然后逝薪,當(dāng)客戶(hù)端收到 [onServiceConnected()](http://developer.android.com/reference/android/content/ServiceConnection.html#onServiceConnected(android.content.ComponentName, android.os.IBinder))回調(diào)時(shí)隅要,會(huì)向服務(wù)發(fā)送一條 Message,并在其send()方法的 replyTo參數(shù)中包含客戶(hù)端的 Messenger董济。

如需查看如何提供雙向消息傳遞的示例步清,請(qǐng)參閱 MessengerService.java
(服務(wù))和MessengerServiceActivities.java
(客戶(hù)端)示例。

綁定到服務(wù)


應(yīng)用組件(客戶(hù)端)可通過(guò)調(diào)用 [bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int))綁定到服務(wù)虏肾。Android 系統(tǒng)隨后調(diào)用服務(wù)的 onBind()方法廓啊,該方法返回用于與服務(wù)交互的 IBinder

綁定是異步的封豪。[bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int))會(huì)立即返回谴轮,“絕對(duì)不會(huì)”**使 IBinder返回客戶(hù)端。要接收 IBinder吹埠,客戶(hù)端必須創(chuàng)建一個(gè) ServiceConnection實(shí)例第步,并將其傳遞給 [bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int))疮装。ServiceConnection
包括一個(gè)回調(diào)方法,系統(tǒng)通過(guò)調(diào)用它來(lái)傳遞 IBinder雌续。

注:只有 Activity斩个、服務(wù)和內(nèi)容提供程序可以綁定到服務(wù)—您無(wú)法從廣播接收器綁定到服務(wù)。

因此驯杜,要想從客戶(hù)端綁定到服務(wù)受啥,必須:

  1. 實(shí)現(xiàn) ServiceConnection。您的實(shí)現(xiàn)必須重寫(xiě)兩個(gè)回調(diào)方法:
  1. 調(diào)用 [bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int))以傳遞 ServiceConnection實(shí)現(xiàn)藤肢。

  2. 當(dāng)系統(tǒng)調(diào)用您的 [onServiceConnected()](http://developer.android.com/reference/android/content/ServiceConnection.html#onServiceConnected(android.content.ComponentName, android.os.IBinder))回調(diào)方法時(shí),您可以使用接口定義的方法開(kāi)始調(diào)用服務(wù)糯景。

  3. 要斷開(kāi)與服務(wù)的連接嘁圈,請(qǐng)調(diào)用 unbindService()
    當(dāng)您的客戶(hù)端被銷(xiāo)毀時(shí)蟀淮,它將取消與服務(wù)的綁定最住,但您應(yīng)該始終在完成與服務(wù)的交互時(shí)或您的 Activity 暫停時(shí)取消綁定,以便服務(wù)能夠在未被占用時(shí)關(guān)閉怠惶。 (下文更詳細(xì)地闡述了綁定和取消綁定的適當(dāng)時(shí)機(jī)涨缚。)

例如,以下代碼段通過(guò)擴(kuò)展 Binder 類(lèi)將客戶(hù)端與上面創(chuàng)建的服務(wù)相連策治,因此它只需將返回的 IBinder
轉(zhuǎn)換為L(zhǎng)ocalService類(lèi)并請(qǐng)求 LocalService實(shí)例:

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

客戶(hù)端可通過(guò)將此 ServiceConnection傳遞至 [bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int))綁定到服務(wù)脓魏。例如:

Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);

附加說(shuō)明

以下是一些有關(guān)綁定到服務(wù)的重要說(shuō)明:

  • 您應(yīng)該始終捕獲 DeadObjectException
    異常,它們是在連接中斷時(shí)引發(fā)的府树。這是遠(yuǎn)程方法引發(fā)的唯一異常
  • 對(duì)象是跨進(jìn)程計(jì)數(shù)的引用
  • 您通常應(yīng)該在客戶(hù)端生命周期的匹配引入 (bring-up) 和退出 (tear-down) 時(shí)刻期間配對(duì)綁定和取消綁定。 例如:
  • 如果您只需要在 Activity 可見(jiàn)時(shí)與服務(wù)交互料按,則應(yīng)在 onStart()期間綁定奄侠,在 onStop()期間取消綁定。
  • 如果您希望 Activity 在后臺(tái)停止運(yùn)行狀態(tài)下仍可接收響應(yīng)载矿,則可在 onCreate()期間綁定垄潮,在onDestroy()期間取消綁定烹卒。請(qǐng)注意,這意味著您的 Activity 在其整個(gè)運(yùn)行過(guò)程中(甚至包括后臺(tái)運(yùn)行期間)都需要使用服務(wù)弯洗,因此如果服務(wù)位于其他進(jìn)程內(nèi)旅急,那么當(dāng)您提高該進(jìn)程的權(quán)重時(shí),系統(tǒng)終止該進(jìn)程的可能性會(huì)增加牡整。

注:通常情況下藐吮,切勿在 Activity 的 onResume()onPause()期間綁定和取消綁定,因?yàn)槊恳淮紊芷谵D(zhuǎn)換都會(huì)發(fā)生這些回調(diào)逃贝,您應(yīng)該使發(fā)生在這些轉(zhuǎn)換期間的處理保持在最低水平谣辞。此外,如果您的應(yīng)用內(nèi)的多個(gè) Activity 綁定到同一服務(wù)沐扳,并且其中兩個(gè) Activity 之間發(fā)生了轉(zhuǎn)換泥从,則如果當(dāng)前 Activity 在下一次綁定(恢復(fù)期間)之前取消綁定(暫停期間),系統(tǒng)可能會(huì)銷(xiāo)毀服務(wù)并重建服務(wù)沪摄。 (Activity文檔中介紹了這種有關(guān) Activity 如何協(xié)調(diào)其生命周期的 Activity 轉(zhuǎn)換躯嫉。)

如需查看更多顯示如何綁定到服務(wù)的示例代碼,請(qǐng)參閱 ApiDemos 中的 RemoteService.java
類(lèi)杨拐。

管理綁定服務(wù)的生命周期


當(dāng)服務(wù)與所有客戶(hù)端之間的綁定全部取消時(shí)祈餐,Android 系統(tǒng)便會(huì)銷(xiāo)毀服務(wù)(除非還使用 [onStartCommand()](http://developer.android.com/reference/android/app/Service.html#onStartCommand(android.content.Intent, int, int))啟動(dòng)了該服務(wù))。因此戏阅,如果您的服務(wù)是純粹的綁定服務(wù)昼弟,則無(wú)需對(duì)其生命周期進(jìn)行管理—Android 系統(tǒng)會(huì)根據(jù)它是否綁定到任何客戶(hù)端代您管理。

不過(guò)奕筐,如果您選擇實(shí)現(xiàn) [onStartCommand()](http://developer.android.com/reference/android/app/Service.html#onStartCommand(android.content.Intent, int, int))回調(diào)方法舱痘,則您必須顯式停止服務(wù),因?yàn)橄到y(tǒng)現(xiàn)在已將服務(wù)視為已啟動(dòng)离赫。在此情況下芭逝,服務(wù)將一直運(yùn)行到其通過(guò) stopSelf()自行停止,或其他組件調(diào)用 stopService()為止渊胸,無(wú)論其是否綁定到任何客戶(hù)端旬盯。

此外,如果您的服務(wù)已啟動(dòng)并接受綁定翎猛,則當(dāng)系統(tǒng)調(diào)用您的 onUnbind()方法時(shí)胖翰,如果您想在客戶(hù)端下一次綁定到服務(wù)時(shí)接收 onRebind()調(diào)用(而不是接收 onBind()調(diào)用),則可選擇返回 true切厘。onRebind()返回空值萨咳,但客戶(hù)端仍在其 [onServiceConnected()](http://developer.android.com/reference/android/content/ServiceConnection.html#onServiceConnected(android.content.ComponentName, android.os.IBinder))
回調(diào)中接收 IBinder。下文圖 1 說(shuō)明了這種生命周期的邏輯疫稿。

**圖 1. **允許綁定的已啟動(dòng)服務(wù)的生命周期

如需了解有關(guān)已啟動(dòng)服務(wù)生命周期的詳細(xì)信息培他,請(qǐng)參閱服務(wù)文檔鹃两。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市舀凛,隨后出現(xiàn)的幾起案子俊扳,更是在濱河造成了極大的恐慌,老刑警劉巖猛遍,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件馋记,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡螃壤,警方通過(guò)查閱死者的電腦和手機(jī)抗果,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)奸晴,“玉大人冤馏,你說(shuō)我怎么就攤上這事〖奶洌” “怎么了逮光?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)墩划。 經(jīng)常有香客問(wèn)我究飞,道長(zhǎng)疫赎,這世上最難降的妖魔是什么划滋? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任俏拱,我火速辦了婚禮,結(jié)果婚禮上察净,老公的妹妹穿的比我還像新娘驾茴。我一直安慰自己,他們只是感情好氢卡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布锈至。 她就那樣靜靜地躺著,像睡著了一般译秦。 火紅的嫁衣襯著肌膚如雪峡捡。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,125評(píng)論 1 297
  • 那天筑悴,我揣著相機(jī)與錄音们拙,去河邊找鬼。 笑死阁吝,一個(gè)胖子當(dāng)著我的面吹牛睛竣,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播求摇,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼射沟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了与境?” 一聲冷哼從身側(cè)響起验夯,我...
    開(kāi)封第一講書(shū)人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎摔刁,沒(méi)想到半個(gè)月后挥转,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡共屈,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年绑谣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拗引。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡借宵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出矾削,到底是詐尸還是另有隱情壤玫,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布哼凯,位于F島的核電站欲间,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏断部。R本人自食惡果不足惜猎贴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蝴光。 院中可真熱鬧她渴,春花似錦、人聲如沸虱疏。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)做瞪。三九已至对粪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間装蓬,已是汗流浹背著拭。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留牍帚,地道東北人儡遮。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像暗赶,于是被迫代替她去往敵國(guó)和親鄙币。 傳聞我的和親對(duì)象是個(gè)殘疾皇子肃叶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • [文章內(nèi)容來(lái)自Developers] 綁定服務(wù)是客戶(hù)端-服務(wù)器接口中的服務(wù)器。綁定服務(wù)可讓組件(例如 Activi...
    岳小川閱讀 1,097評(píng)論 0 1
  • [文章內(nèi)容來(lái)自Developers] AIDL(Android 接口定義語(yǔ)言)與您可能使用過(guò)的其他 IDL 類(lèi)似十嘿。...
    岳小川閱讀 424評(píng)論 0 3
  • 服務(wù)基本上分為兩種形式 啟動(dòng) 當(dāng)應(yīng)用組件(如 Activity)通過(guò)調(diào)用 startService() 啟動(dòng)服務(wù)時(shí)...
    pifoo閱讀 1,270評(píng)論 0 8
  • 轉(zhuǎn)載請(qǐng)注明出處:http://www.reibang.com/p/e6867aa8f267[https://www...
    朋永閱讀 1,842評(píng)論 0 2
  • 凝望她的眸子如天邊黯淡星子 夜色下的影子伴著晚風(fēng)吹落的葉子 如斷了線(xiàn)的眼淚珠子心碎的像玻璃渣子 往事如卡住的錄影帶...
    卻悔閱讀 223評(píng)論 13 3