Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android使用Messenger實現進程間雙向通信

Android使用Messenger實現進程間雙向通信

編輯:關於Android編程

在了解本文即將學到的技能外,有些知識還是有必要提前知道的,這樣才會更容易理解本文即將講到的知識點。需要提前預熱的知識點:

1、Android四大組件之一Service,要知道怎樣去寫一個Service,Service有哪兩種啟動方式;

2、Android Service啟動方式之Bound Service;

3、Android基礎知識之Messenger;

掌握了這三個知識點,就可以快速入手使用Messenger進行進程間通信了。

一、知識點回顧之Service

我們來看看官方文檔關於對Service最權威的解釋:

Service是一個應用程序組件,它能夠在後台執行一些耗時較長的操作,並且不提供用戶界面。服務能被其它應用程序的組件啟動,即使用戶切換到另外的應用時還能保持後台運行。此外,應用程序組件還能與服務綁定,並與服務進行交互,甚至能進行進程間通信(IPC)。 比如,服務可以處理網絡傳輸、音樂播放、執行文件I/O、或者與content provider進行交互,所有這些都是後台進行的。

服務有以下兩種基本類型:

Started

如果一個應用程序組件(比如一個activity)通過調用startService()來啟動服務,則該服務就是被“started”了。一旦被啟動,服務就能在後台一直運行下去,即使啟動它的組件已經被銷毀了。 通常,started的服務執行單一的操作並且不會向調用者返回結果。比如,它可以通過網絡下載或上傳文件。當操作完成後,服務應該自行終止。

Bound

如果一個應用程序組件通過調用bindService()綁定到服務上,則該服務就是被“bound”了。bound服務提供了一個客戶端/服務器接口,允許組件與服務進行交互、發送請求、獲取結果,甚至可以利用進程間通信(IPC)跨進程執行這些操作。綁定服務的生存期和被綁定的應用程序組件一致。 多個組件可以同時與一個服務綁定,不過所有的組件解除綁定後,服務也就會被銷毀。

雖然本文對這兩種類型的服務是分別進行簡要描述的,但是你的服務仍可以同時用兩種方式工作——可以是started(一直運行下去),同時也能被綁定。 只會存在一點麻煩,是否兩個回調方法都要實現:實現onStartCommand()以允許組件啟動服務、實現onBind()以允許綁定。

無論你的應用程序是started、bound、還是兩者都支持,任何應用程序組件都可以使用此服務(即使是從另一個獨立的應用程序中), 同樣,任何組件都可以用這種方式使用一個activity——通過一個Intent啟動。不過,也可以在manifest文件中把服務聲明為私有private的,以便阻止其它應用程序的訪問。

注意:服務運行於宿主進程的主線程中——不創建自己的線程並且不是運行在單獨的進程中(除非你明確指定)。 這意味著,如果你的服務要執行一些很耗CPU的工作或者阻塞的操作(比如播放MP3或網絡操作),你應該在服務中創建一個新的線程來執行這些工作。 利用單獨的線程,將減少你的activity發生應用程序停止響應(ANR)錯誤的風險。

Service的兩種啟動模式

在創建一個Service之前,需要繼承Service類,重寫一些回調方法。Service最重要的兩個回調方法就是onStartCommand()和onBind(),基於這兩個方法的重寫也就決定了Service的啟動模式。如果onBind()方法中返回null,說明Service需要通過startService()啟動,如果onBind()返回一個IBinder,說明Service可以通過bindService()進行服務綁定,從而啟用Service;

onStartCommand()

當其它組件,比如一個activity,通過調用startService()請求started方式的服務時,系統將會調用本方法。 一旦本方法執行,服務就被啟動,並在後台一直運行下去。 如果你的代碼實現了本方法,你就有責任在完成工作後通過調用stopSelf()或stopService()終止服務。 (如果你只想提供bind方式,那就不需要實現本方法。)

onBind()

當其它組件需要通過bindService()綁定服務時(比如執行RPC),系統會調用本方法。 在本方法的實現代碼中,你必須返回IBinder來提供一個接口,客戶端用它來和服務進行通信。 你必須確保實現本方法,不過假如你不需要提供綁定,那就返回null即可。

Service其他幾個重寫方法:

onCreate()

當服務第一次被創建時,系統會調用本方法,用於執行一次性的配置工作(之前已調用過onStartCommand()或onBind()) 了。如果服務已經運行,則本方法就不會被調用。

onDestroy()

當服務用不上了並要被銷毀時,系統會調用本方法。 你的服務應該實現本方法來進行資源的清理工作,諸如線程、已注冊的偵聽器listener和接收器receiver等等。 這將是服務收到的最後一個調用。

如果組件通過調用startService()(這會導致onStartCommand()的調用)啟動了服務,那麼服務將一直保持運行,直至自行用stopSelf()終止或由其它組件調用stopService()來終止它。

如果組件調用bindService()來創建服務(那onStartCommand()就不會被調用),則服務的生存期就與被綁定的組件一致。一旦所有客戶端都對服務解除了綁定,系統就會銷毀該服務。

創建一個started服務

started服務是指其它組件通過調用startService()來啟動的服務,這會引發對該服務onStartCommand()方法的調用。

一旦服務被啟動started,它就擁有了自己的生命周期,這是獨立於啟動它的組件的。並且它能夠在後台一直運行下去,即使啟動它的組件已被銷毀 也是如此。 因此,服務應該能夠在完成工作後自行終止,通過調用stopSelf()即可,或者由其它組件通過調用stopService()也可以。

諸如activity之類的應用程序組件,可以通過調用startService()啟動服務,並傳入一個給出了服務和服務所需數據的Intent對象。服務將在onStartCommand()方法中接收到該Intent對象。

Service

這是所有服務的基類。如果你要擴展該類,則很重要的一點是:請在其中創建一個新的線程來完成所有的服務工作。 因為服務默認是使用應用程序的主線程的,這會降低應用程序中activity的運行性能。

擴展Service類

package com.lc.proctice.androidstudioproctice.myservice;

import android.app.Service;

import android.content.Intent;

import android.os.Handler;

import android.os.HandlerThread;

import android.os.IBinder;

import android.os.Looper;

import android.os.Message;

import android.os.Process;

import android.support.annotation.Nullable;

/**

* Created by licheng on 24/7/16.

*/

public class HelloService extends Service {

private ServiceHandler serviceHandler;

private Looper looper;

/** 處理從線程獲取到的消息 **/

private final class ServiceHandler extends Handler{

public ServiceHandler(Looper looper) {

super(looper);

}

@Override

public void handleMessage(Message msg) {

/** 線程等待5秒 **/

long endTime = System.currentTimeMillis() + 5*1000;

while (System.currentTimeMillis() < endTime) {

synchronized (this) {

try {

wait(endTime - System.currentTimeMillis());

} catch (Exception e) {

}

}

}

/** 根據startId停止當前服務,這樣我們就不必要在處理其他工作的過程中來終止這個服務 **/

stopSelf(msg.arg1);

}

}

@Override

public void onCreate() {

super.onCreate();

/** Service運行在主線程,為了不阻塞線程,我們需要另起線程,還可以賦予線程優先級 **/

HandlerThread handlerThread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND);

handlerThread.start();

/** 獲取線程的Looper隊列用於Handler **/

looper = handlerThread.getLooper();

serviceHandler = new ServiceHandler(looper);

}

@Override

public void onDestroy() {

super.onDestroy();

}

@Override

public int onStartCommand(Intent intent, int flags, int startId) {

/** 發送消息,傳入當前服務startId **/

Message msg = serviceHandler.obtainMessage();

msg.arg1 = startId;

serviceHandler.sendMessage(msg);

/** 如果服務被殺死,從這裡返回後服務將被重啟 **/

return START_STICKY;

}

@Nullable

@Override

public IBinder onBind(Intent intent) {

/** 如果不支持綁定,就返回Null **/

return null;

}

}

關於HandlerThread,可以參考這篇博文Android HandlerThread完全解析

啟動服務

從activity或其它應用程序組件中可以啟動一個服務,調用startService()並傳入一個Intent(指定所需啟動的服務)即可。Android系統將調用服務的onStartCommand()方法,並傳入該Intent(你永遠都不應該直接去調用onStartCommand()。)

例如,一個activity可以用一個顯式的intent通過startService()啟動上一節的示例服務(HelloSevice):

Intent intent = new Intent(this, HelloService.class);

startService(intent);

startService()方法會立即返回,Android系統會去調用服務的onStartCommand()方法。如果服務還未運行,系統會首先調用onCreate(),然後再去調用onStartCommand()。

如果服務不同時支持綁定,那麼通過startService()傳入的intent將是應用程序組件與服務進行交互的唯一途徑。 當然,如果你期望服務能返回結果,那啟動服務的客戶端可以創建一個PendingIntent來獲得一個廣播broadcast(利用getBroadcast()),並把它放入啟動服務的Intent並傳到服務中去。然後服務就會用這個broadcast來傳遞結果。

多個啟動服務的請求將會引發服務onStartCommand()方法的多次調用。不過,只有一個終止服務的請求(用stopSelf()或stopService())會被接受並執行。

終止服務

一個started服務必須自行管理生命周期。也就是說,系統不會終止或銷毀這類服務,除非必須恢復系統內存並且服務返回後一直維持運行。 因此,服務必須通過調用stopSelf()自行終止,或者其它組件可通過調用stopService()來終止它。

用stopSelf()或stopService()的終止請求一旦發出,系統就會盡快銷毀服務。

不過,如果你的服務要同時處理多個onStartCommand()請求,那在處理啟動請求的過程中,你就不應該去終止服務,因為你可能接收到了一個新的啟動請求(在第一個請求處理完畢後終止服務將停止第二個請求的處理。 為了避免這個問題,你可以用stopSelf(int)來確保終止服務的請求總是根據最近一次的啟動請求來完成。 也就是說,當你調用stopSelf(int)時,你把啟動請求ID(發送給onStartCommand()的startId)傳給了對應的終止請求。這樣,如果服務在你可以調用stopSelf(int)時接收到了新的啟動請求,則ID將會不一樣,服務將不會被終止。

注意:

當服務完成工作後,你的應用程序應該及時終止它,這點非常重要。這樣可以避免系統資源的浪費,並能節省電池的電力。 必要時,其它組件可以通過調用stopService()來終止服務。即使你的服務允許綁定,你也必須保證它在收到對onStartCommand()的調用時能夠自行終止。

啟動服務前還需要在manifest.xml文件聲明Service,這樣才能保證服務正常工作。

要聲明你的服務,把元素作為子元素加入到元素中去即可。例如:

...

...

在元素中可以包含很多其它屬性,比如定義啟動服務所需權限、服務運行的進程之類的屬性。

創建一個Bound服務

bound服務是指允許被應用程序組件綁定的服務,通過調用bindService()可以完成綁定,用於創建一個長期存在的連接(並且一般不再允許組件通過調用startService()來start服務。

當應用程序中的activity或其它組件需要與服務進行交互,或者應用程序的某些功能需要暴露給其它應用程序時,你應該創建一個bound服務,並通過進程間通信(IPC)來完成。

要創建一個bound服務,你必須實現onBind()回調方法,並返回一個IBinder對象,此對象定義了與服務進行通信的接口。 然後,其它應用程序組件可以調用bindService()來獲得接口並調用服務中的方法。 服務只在為綁定的應用程序組件工作時才會存活,因此,只要沒有組件綁定到服務,系統就會自動銷毀服務(你不需要像started服務中那樣通過onStartCommand()來終止一個bound服務)。

要創建一個bound服務,首先必須定義好接口,用於指明客戶端如何與服務進行通信。 這個客戶端與服務之間的接口必須是一個IBinder對象的實現,並且你的服務必須在onBind()回調方法中返回這個對象。一旦客戶端接收到這個IBinder,它就可以通過這個接口來與服務進行交互。

同一個服務可以被多個客戶端綁定。當客戶端完成交互時,會調用unbindService()來解除綁定。一旦不存在客戶端與服務綁定時,系統就會銷毀該服務。

擴展Service類

package com.lc.proctice.androidstudioproctice.myservice;

import android.app.Service;

import android.content.Intent;

import android.os.Binder;

import android.os.IBinder;

import android.util.Log;

/**

* Created by licheng on 18/8/15.

*/

public class BindService extends Service {

private static final String TAG = "BindService";

private int count=0;

private boolean quit=false;

private Thread thread;

private MyBinder binder=new MyBinder();

/** 創建和和客戶端通信的Binder,公開它的方法,便於客戶端調用 **/

public class MyBinder extends Binder{

public int getCount(){

return count;

}

}

@Override

public void onCreate() {

super.onCreate();

Log.v(TAG, "service is onCreate");

/** 另起線程 **/

thread = new Thread(new Runnable() {

@Override

public void run() {

while (!quit) {

try {

thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

count++;

}

}

});

thread.start();

}

@Override

public IBinder onBind(Intent intent) {

Log.v(TAG, "Service is Binded");

return binder;

}

@Override

public void onStart(Intent intent, int startId) {

super.onStart(intent, startId);

}

@Override

public int onStartCommand(Intent intent, int flags, int startId) {

Log.v(TAG, "Service is started");

return super.onStartCommand(intent, flags, startId);

}

@Override

public boolean onUnbind(Intent intent) {

Log.v(TAG, "Service is Unbinded");

return true;

}

@Override

public void onDestroy() {

Log.v(TAG,"service is destroyed");

this.quit = true;

}

}

綁定服務

應用程序組件(客戶端)可以通過調用bindService()來綁定服務。然後Android系統會調用服務的onBind()方法,返回一個用於和服務進行交互的IBinder。

綁定是異步進行的。bindService()將立即返回,並不會向客戶端返回IBinder。為了接收IBinder,客戶端必須創建一個ServiceConnection的實例,並把它傳給bindService()。ServiceConnection包含了一個回調方法,系統將會調用該方法來傳遞客戶端所需的那個IBinder。

注意:

只有activity、服務和content provider才可以綁定到服務上——你不能從廣播接收器(broadcast receiver)中綁定服務。

因此,要把客戶端綁定到服務上,你必須:

實現ServiceConnection。

你的實現代碼必須重寫兩個回調方法:

onServiceConnected()

系統調用該方法來傳遞服務的onBind()方法所返回的IBinder。

onServiceDisconnected()

當與服務的聯接發生意外中斷時,比如服務崩潰或者被殺死時,Android系統將會調用該方法。客戶端解除綁定時,不會調用該方法。

調用bindService(),傳入已實現的ServiceConnection。

當系統調用你的onServiceConnected()回調方法時,你可以利用接口中定義的方法開始對服務的調用。

要斷開與服務的聯接,請調用unbindService()。

當客戶端被銷毀時,與服務的綁定也將解除。但與服務交互完畢後,或者你的activity進入pause狀態時,你都應該確保解除綁定,以便服務能夠在用完後及時關閉。(綁定和解除綁定的合適時機將在後續章節中繼續討論。)

為了啟動上面的BindService,我們需要在客戶端寫一個ServiceConnection

private ServiceConnection connection = new ServiceConnection() {

@Override

public void onServiceConnected(ComponentName name, IBinder service) {

Log.i(TAG, "--Service Connected--");

// 取得Service對象中的Binder對象

binder = (BindService.MyBinder) service;

}

@Override

public void onServiceDisconnected(ComponentName name) {

Log.i(TAG, "--Service Disconnected--");

}

};

啟動服務

Intent intent = new Intent(ServiceActivity.this, BindService.class);

bindService(intent, connection, Service.BIND_AUTO_CREATE);

注意:BindService需要在manifest.xml文件中聲明。

以上關於Service的兩種啟動模式就講到這裡啦,關於Android Service 的Bound服務,這裡也很有必要將清楚,因為在介紹了這麼多准備知識後,我們還沒有進入到這篇文章的主題,使用Messenger進行進程間通信。

Android Bound服務

bound服務是客戶端-服務器模式的服務。bound服務允許組件(比如activity)對其進行綁定、發送請求、接收響應、甚至進行進程間通信(IPC)。 bound服務一般只在為其它應用程序組件服務期間才是存活的,而不會一直在後台保持運行。

bound服務是Service類的一種實現,它允許其它應用程序與其綁定並交互。為了讓服務支持綁定,你必須實現onBind()回調方法。這個方法返回一個IBinder對象,此對象定義了客戶端與服務進行交互時所需的編程接口。

客戶端可以通過調用bindService()方法來綁定服務。在調用時,必須提供一個ServiceConnection的實現代碼,用於監控與服務的聯接。bindService()將會立即返回,沒有返回值。但是Android系統在創建客戶端與服務之間的聯接時,會調用ServiceConnection中的onServiceConnected()方法,傳遞一個IBinder,客戶端將用它與服務進行通信。

多個客戶端可以同時聯接到一個服務上。不過,只有在第一個客戶端綁定時,系統才會調用服務的onBind()方法來獲取IBinder。然後,系統會向後續請求綁定的客戶端傳送這同一個IBinder,而不再調用onBind()。

當最後一個客戶端解除綁定後,系統會銷毀服務(除非服務同時是通過startService()啟動的)。

當你實現自己的bound服務時,最重要的工作就是定義onBind()回調方法所返回的接口。定義服務IBinder接口的方式有好幾種,後續章節將會對每種技術進行論述。

定義IBinder的三種方式

創建一個支持綁定的服務時,你必須提供一個IBinder,用作客戶端和服務間進行通信的編程接口。定義這類接口的方式有三種:

擴展Binder類

如果服務是你的應用程序所私有的,並且與客戶端運行於同一個進程中(通常都是如此),你應該通過擴展Binder類來創建你的接口,並從onBind()返回一個它的實例。客戶端接收該Binder對象並用它來直接訪問Binder甚至Service中可用的公共(public)方法。

如果你的服務只是為你自己的應用程序執行一些後台工作,那這就是首選的技術方案。不用這種方式來創建接口的理由只有一個,就是服務要被其它應用程序使用或者要跨多個進程使用。

使用Messenger

如果你需要接口跨越多個進程進行工作,可以通過Messenger來為服務創建接口。在這種方式下,服務定義一個響應各類消息對象Message的Handler。此Handler是Messenger與客戶端共享同一個IBinder的基礎,它使得客戶端可以用消息對象Message向服務發送指令。此外,客戶端還可以定義自己的Message,以便服務能夠往回發送消息。

這是執行進程間通信(IPC)最為簡便的方式,因為Messenger會把所有的請求放入一個獨立進程中的隊列,這樣你就不一定非要把服務設計為線程安全的模式了。

使用AIDL

Android接口定義語言AIDL(Android Interface Definition Language)完成以下的所有工作:將對象解析為操作系統可識別的原始形態,並將它們跨進程序列化(marshal)以完成IPC。前一個使用Messenger的方式,實際上也是基於AIDL的,它用AIDL作為底層結構。如上所述,Messenger將在一個單獨的進程中創建一個包含了所有客戶端請求的隊列,這樣服務每次就只會收到一個請求。可是,如果想讓你的服務能同時處理多個請求,那你就可以直接使用AIDL。這種情況下,你的服務必須擁有多線程處理能力,並且是以線程安全的方式編寫的。

要直接使用AIDL,你必須創建一個.aidl文件,其中定義了編程的接口。Android SDK 工具使用此文件來生成一個抽象類(abstract class),其中實現了接口及對IPC的處理,然後你就可以在自己的服務中擴展該類。

注意:絕大多數應用程序都不應該用AIDL來創建bound服務,因為這可能需要多線程處理能力並且會讓代碼變得更為復雜。 因此,AIDL對絕大多數應用程序都不適用,並且本文也不會討論如何在服務中使用它的內容。

上文BindService中的Ibinder實現方式就采用了方式一,擴展Binder類,實現了客戶端和服務端的數據交互。

接下來進入本文的正題了,用方式二實現IBinder,即通過Messenger實現IBinder,進一步實現客戶端和服務端的數據雙向交互。

使用Messenger

如果你的服務需要與遠程進程進行通信,那你可以使用一個Messenger來提供服務的接口。這種技術能讓你無需使用AIDL就能進行進程間通信(IPC)。

以下概括了Messenger的使用方法:

服務實現一個Handler,用於客戶端每次調用時接收回調。

此Handler用於創建一個Messenger對象(它是一個對Handler的引用)。

此Messenger對象創建一個IBinder,服務在onBind()中把它返回給客戶端。

客戶端用IBinder將Messenger(引用服務的Handler)實例化,客戶端用它向服務發送消息對象Message。

服務接收Handler中的每個消息Message——確切的說,是在handleMessage()方法中接收。

通過這種方式,客戶端不需要調用服務中的“方法”。取而代之的是,客戶端發送“消息”(Message對象),服務則接收位於Handler中的這個消息。

擴展Service類

package com.lc.proctice.androidstudioproctice.myservice;

import android.app.Service;

import android.content.Intent;

import android.os.Handler;

import android.os.IBinder;

import android.os.Message;

import android.os.Messenger;

import android.os.RemoteException;

import android.support.annotation.Nullable;

import android.widget.Toast;

/**

* Created by licheng on 23/7/16.

*/

public class MessengerService extends Service {

public static final int MSG_SAY_HELLOW = 1;

/**

* 從客戶端接收消息的Handler

*/

class IncomingHandler extends Handler{

@Override

public void handleMessage(Message msg) {

switch (msg.what){

case MSG_SAY_HELLOW:

Toast.makeText(getApplicationContext(),"hellow",Toast.LENGTH_SHORT).show();

repalyMessenger = msg.replyTo;

/** 開啟一個線程模擬,三秒後回傳服務器數據給客戶端 **/

new ReplayThread().start();

break;

default:

super.handleMessage(msg);

}

}

}

/**

* 向客戶端公布的用於向IncomingHandler發送信息的Messager

*/

final Messenger messenger = new Messenger(new IncomingHandler());

/** 用於接收客戶端回傳來的messenger **/

private Messenger repalyMessenger = null;

@Override

public void onCreate() {

super.onCreate();

}

@Override

public void onDestroy() {

super.onDestroy();

}

@Override

public int onStartCommand(Intent intent, int flags, int startId) {

return super.onStartCommand(intent, flags, startId);

}

/**

* 當綁定到服務時,我們向Messager返回接口,

* 用於向服務發送消息

*/

@Nullable

@Override

public IBinder onBind(Intent intent) {

return messenger.getBinder();

}

private class ReplayThread extends Thread{

@Override

public void run() {

try {

Thread.sleep(3000);

} catch (InterruptedException e) {

e.printStackTrace();

}

/** 服務端向客戶端發送消息 **/

Message msg = new Message();

msg.what = 111;

try {

if(null != repalyMessenger)

repalyMessenger.send(msg);

} catch (RemoteException e) {

e.printStackTrace();

}

}

}

}

客戶端啟動服務

package com.lc.proctice.androidstudioproctice.myservice;

import android.app.Activity;

import android.content.ComponentName;

import android.content.Intent;

import android.content.ServiceConnection;

import android.os.Bundle;

import android.os.Handler;

import android.os.IBinder;

import android.os.Message;

import android.os.Messenger;

import android.os.RemoteException;

import android.view.View;

import android.widget.Button;

import android.widget.Toast;

import com.lc.proctice.androidstudioproctice.R;

/**

* Created by licheng on 23/7/16.

*/

public class MessengerActivity extends Activity {

private Button btnGetMessage;

private boolean mBound;

/** 用於和服務通信的messager **/

private Messenger mService = null;

/** 用於回傳的messenger **/

private Messenger sendMessenger = null;

/** 用於處理服務端向客戶端發送的消息 **/

private Handler handler = new Handler(){

@Override

public void handleMessage(Message msg) {

if(msg.what == 111){

Toast.makeText(MessengerActivity.this, "服務器給客戶端回傳的消息", Toast.LENGTH_SHORT).show();

}

}

};

private ServiceConnection connection = new ServiceConnection() {

@Override

public void onServiceConnected(ComponentName name, IBinder service) {

// 與服務建立聯接後將會調用本方法,

// 給出用於和服務交互的對象。

// 我們將用一個Messenger來與服務進行通信,

// 因此這裡我們獲取到一個原始IBinder對象的客戶端實例。

mBound = true;

mService = new Messenger(service);

}

@Override

public void onServiceDisconnected(ComponentName name) {

mService = null;

mBound = false;

}

};

/** 客戶端向服務端發送消息 **/

public void sayHello(){

if(!mBound) return;

sendMessenger = new Messenger(handler);

// 創建並向服務發送一個消息,用到了已約定的'what'值

Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLOW, 0, 0);

try {

msg.replyTo = sendMessenger;

mService.send(msg);

} catch (RemoteException e) {

e.printStackTrace();

}

}

@Override

protected void onStart() {

super.onStart();

/** 綁定服務 **/

bindService(new Intent(this, MessengerService.class), connection, BIND_AUTO_CREATE);

}

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_messenger);

btnGetMessage = (Button) findViewById(R.id.btnGetMessage);

btnGetMessage.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

sayHello();

}

});

}

@Override

protected void onStop() {

super.onStop();

if(mBound){

unbindService(connection);

mBound = false;

}

}

}

注意:如果你需要服務進行響應,那你還需要在客戶端創建一個Messenger。然後,當客戶端接收到onServiceConnected()回調後,它再發送一個消息Message給服務,消息的send()方法中的replyTo參數裡包含了客戶端的Messenger。

運行MessengerActivity,點擊進程通信按鈕,就可以首先看到客戶端發送到服務端的“hellow”消息,3秒後,就可以看到服務端發送給客戶端的“服務端給客戶端回傳的消息”消息,大公告成,使用Messenger實現了Activity和Service的數據雙向互通。

與AIDL相比,當你需要進行IPC時,使用Messenger要比用AIDL實現接口要容易些,因為Messenger會把所有調用服務的請求放入一個隊列。而純粹的AIDL接口會把這些請求同時發送給服務,這樣服務就必須要能夠多線程運行。

對於絕大多數應用程序而言,服務沒有必要多線程運行,因此利用Messenger可以讓服務一次只處理一個調用。如果 你的服務非要多線程運行,那你就應該用AIDL來定義接口。

關於使用AIDL實現進程間的通信教程後面會貼出來,敬請期待。

本文參考資料:Google官方文檔http://www.android-doc.com/guide/components/bound-services.html

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved