一、 本地Service與Binder的使用
本地Service和Activity通信可以通過Binder實現,先在Service中繼承Binder實現自己的Binder類。
- class MyBinder extends Binder {
- public LocalBindService getService() {
- return LocalBindService.this;
- }
- }
然後在Service中的onBind()中返回這個Binder的實例。
- @Override
- public IBinder onBind(Intent intent) {
- Log.i(TAG,"onBind");
- doSomeTask();
- return mMyBinder;
- }
在Activity中,通過onServiceConnected()獲取Binder實例由,Binder實例可以得到Service實例。這樣可以調用Service中公共方法,但有時需要Service主動通知Activity做一些更新UI操作。這時需要在Service中定義一個接口,然後Service可以通過這個接口來回調Activity裏面的方法。
- interface ProgressChangeListener {
- void updateProgress(int value);
- }
- public void setProgressChangeListener(ProgressChangeListener progressChangeListener) {
- mProgressChangeListener = progressChangeListener;
- }
在Activity中:
- private ServiceConnection mConnection = new ServiceConnection() {
- @Override
- public void onServiceDisconnected(ComponentName name) {
- }
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- LocalBindService.MyBinder myBinder = (LocalBindService.MyBinder) service;
- LocalBindService localBindService =myBinder.getService();
- //通過Binder與Service通信
- localBindService.setProgressChangeListener(new LocalBindService.ProgressChangeListener() {
- @Override
- public void updateProgress(int value) {
- mBindProgressBar.setProgress(value);
- }
- });
- }
- };
二、 通過Messenger與遠程進程通信
Messenger可以實現Service與遠程進程通信,Messenger隊列所有的請求放在一個單獨的線程當中,因此,Service每次只能處理一個請求。
1、Service實現了一個Handler,用來接收和處理客戶端發送過來的消息。
- class MessengerHandler extends Handler {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_REGISTER_CLIENT:
- mClients.add(msg.replyTo);
- break;case MSG_UNREGISTER_CLIENT:
- try {
- msg.replyTo.send(Message.obtain(null,
- MSG_UNREGISTER_CLIENT, 8888, 0));
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- mClients.remove(msg.replyTo);
- break;case MSG_SET_VALUE:
- mValue = msg.arg1;
- for (int i = mClients.size() - 1; i >= 0; i--) {
- try {
- mClients.get(i).send(Message.obtain(null,
- MSG_SET_VALUE, mValue, 0));
- } catch (RemoteException e) {
- mClients.remove(i);
- }
- }
- break;default:
- super.handleMessage(msg);
- }
- }
- }
2、創建一個包含Handler引用Messenger對象。
- private MessengerHandler mMessengerHandler = new MessengerHandler();
- private Messenger mMessenger = new Messenger(mMessengerHandler);
3、通過Messenger 得到Binder,並從onBind()方法將其返回。
- @Override
- public IBinder onBind(Intent intent) {
- return mMessenger.getBinder();
- }
4、客戶端在ServiceConnection中,使用IBinder來實例化這個Messenger,用這個Messenger向Service發送Message對象,Service 中的Handler將處理這個Message對象。
- private ServiceConnection mServiceConnection=new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- mMessengerService=new Messenger(service);
- mCallbackText.setText("Attached.");
- try {Message msg = Message.obtain(null,
- MessengerService.MSG_REGISTER_CLIENT);
- msg.replyTo = mMessenger;
- mMessengerService.send(msg);
- msg = Message.obtain(null,
- MessengerService.MSG_SET_VALUE, this.hashCode(), 0);
- mMessengerService.send(msg);
- } catch (RemoteException e) {
- } Toast.makeText(MessengerActivity.this, "remote_service_connected",
- Toast.LENGTH_SHORT).show();
- }
- @Override
- public void onServiceDisconnected(ComponentName name) {
- mCallbackText.setText("Disconnected.");
- Toast.makeText(MessengerActivity.this, "remote_service_disconnected",
- Toast.LENGTH_SHORT).show();
- }
- };
5、客戶端同樣定義一個Handler對象,用於處理服務端返回的Message對象,同時構造一個包含這個Handler引用的Messenger對象,在向服務端發送消息時,將客戶端的Messenger對象賦值給消息的replyTo,這樣,服務端通過replyTo向客戶端發送的Message對象。
通過這種方法,客戶端和服務端可以相互傳遞Message對象。
- <span style="font-size:14px;">private Handler mHandler=new Handler(){
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MessengerService.MSG_SET_VALUE:
- mCallbackText.setText("Received from service: " + msg.arg1);
- break; case MessengerService.MSG_UNREGISTER_CLIENT:
- Toast.makeText(MessengerActivity.this, "Received from service: "+msg.arg1,
- Toast.LENGTH_SHORT).show();
- default:
- super.handleMessage(msg);
- }
- }
- };
- private Messenger mMessenger=new Messenger(mHandler);</span>
三、 通過AIDL與遠程進程通信
AIDL(Android InterfaceDefinition Language)是Android接口定義語言的意思,它可以用於讓某個Service與多個應用程序組件之間進行跨進程通信,從而可以實現多個應用程序共享同一個Service的功能。
如果需要Service同時接收多個請求,Messenger不能滿足需求,需要使用AIDL。在這種情況下,Service必須有能力執行多個線程,必須爲Service實現線程安全。
1.創建一個.aidl
AIDL參數和返回值可以是任何類型,甚至其他AIDL生成的接口。 使用Java語言構建一個.aidl文件,每個.aild文件必須定義一個單獨的接口,並且使用確定的聲明和方法簽名。
- / IRemoteService.aidl
- package com.example.xujiang.servicelearn;
- import com.example.xujiang.servicelearn.IRemoteServiceCallback;
- // Declare any non-default types here with import statements
- interface IRemoteService {
- void registerCallback(IRemoteServiceCallback cb);
- void unregisterCallback(IRemoteServiceCallback cb);
- }
2. 繼承這個接口
Android SDK工具會爲.aidl文件生成一個接口。這個接口有一個叫Stub的內部抽象類。需要寫一個類繼承這個Stub類並且實現這些方法,在onBind返回這個類的實例對象。
- private final IRemoteService.Stub mRemoteServiceStub=new IRemoteService.Stub() {
- @Override
- public void registerCallback(IRemoteServiceCallback cb) throws RemoteException {
- if (cb!=null){
- mCallbacks.register(cb);
- }
- }
- @Override
- public void unregisterCallback(IRemoteServiceCallback cb) throws RemoteException {
- if (cb!=null){
- mCallbacks.unregister(cb);
- }
- }
- };
3.把接口暴露給客戶端
繼承一個Service並且重寫onBind()來返回實現的Stub類。客戶端通過asInterface方法得到接口的引用,從而可以調用接口裏面的方法。
如果需要在進程間傳遞類,類必須支持Parcelable 接口。支持Parcelable 接口是因爲Android系統需要分解對象爲可以穿越進程的原語。
- @Override
- public IBinder onBind(Intent intent) {
- Log.i(TAG,"onBind");
- return mRemoteServiceStub;
- }
4.客戶端調用
- private ServiceConnection mConnection = new ServiceConnection() {
- public void onServiceConnected(ComponentName className,
- IBinder service) {
- mRemoteService = IRemoteService.Stub.asInterface(service);
- mCallbackText.setText("Attached.");
- try {
- mRemoteService.registerCallback(mServiceCallback);
- } catch (RemoteException e) {
- }Toast.makeText(AIDLActivity.this, "remote_service_connected",
- Toast.LENGTH_SHORT).show();
- }
- public void onServiceDisconnected(ComponentName className) {
- mRemoteService = null;
- mCallbackText.setText("Disconnected.");
- Toast.makeText(AIDLActivity.this, "remote_service_disconnected",
- Toast.LENGTH_SHORT).show();
- }
- };