Android中使用AIDL時的跨程序回撥—Server回撥Client
首先建立在server端建立兩個aidl檔案
ITaskCallback.aidl 用於存放要回調client端的方法
- package com.cmcc.demo.server;
- interface ITaskCallback {
- void actionPerformed(int actionId);
- }
ITaskBinder.aidl 用於存放供給client端呼叫的方法
- package com.cmcc.demo.server;
- import com.cmcc.demo.server.ITaskCallback;
- interface ITaskBinder {
- boolean isTaskRunning();
- void stopRunningTask();
- void registerCallback(ITaskCallback cb);
- void unregisterCallback(ITaskCallback cb);
- }
接著建立服務端,要實現回撥,需要新建RemoteCallbackList物件(一個儲存回撥物件的列表),通過類似傳送廣播的形式來實現回撥
MyService.java
- package com.cmcc.demo.server;
- import com.cmcc.demo.server.ITaskBinder;
- import com.cmcc.demo.server.ITaskCallback;
- import android.app.Service;
- import android.content.Intent;
- import android.os.IBinder;
- import android.os.RemoteCallbackList;
- import android.os.RemoteException;
- import android.util.Log;
- publicclass MyService extends Service {
- privatestaticfinal
- @Override
- publicvoid onCreate() {
- printf("service create");
- }
- @Override
- publicvoid onStart(Intent intent, int startId) {
- printf("service start id=" + startId);
- callback(startId);
- }
- @Override
- public IBinder onBind(Intent t) {
- printf("service on bind");
- return mBinder;
- }
- @Override
- publicvoid onDestroy() {
- printf("service on destroy");
- super.onDestroy();
- }
- @Override
- publicboolean onUnbind(Intent intent) {
- printf("service on unbind");
- returnsuper.onUnbind(intent);
- }
- publicvoid onRebind(Intent intent) {
- printf("service on rebind");
- super.onRebind(intent);
- }
- privatevoid printf(String str) {
- Log.v(TAG, "###################------ " + str + "------");
- }
- void callback(int val) {
- finalint N = mCallbacks.beginBroadcast();
- for (int i=0; i<N; i++) {
- try {
- mCallbacks.getBroadcastItem(i).actionPerformed(val);
- }
- catch (RemoteException e) {
- // The RemoteCallbackList will take care of removing
- // the dead object for us.
- }
- }
- mCallbacks.finishBroadcast();
- }
- privatefinal ITaskBinder.Stub mBinder = new ITaskBinder.Stub() {
- publicvoid stopRunningTask() {
- }
- publicboolean isTaskRunning() {
- returnfalse;
- }
- publicvoid registerCallback(ITaskCallback cb) {
- if (cb != null) {
- mCallbacks.register(cb);
- }
- }
- publicvoid unregisterCallback(ITaskCallback cb) {
- if(cb != null) {
- mCallbacks.unregister(cb);
- }
- }
- };
- final RemoteCallbackList <ITaskCallback>mCallbacks = new RemoteCallbackList <ITaskCallback>();
- }
最後建立客戶端,使用aidl,實現回撥方法。
MyActivity.java
- package com.cmcc.demo;
- import android.app.Activity;
- import android.content.ComponentName;
- import android.content.Intent;
- import android.content.ServiceConnection;
- import android.os.Bundle;
- import android.os.IBinder;
- import android.os.RemoteException;
- import android.util.Log;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- import com.cmcc.demo.server.*;
- publicclass MyActivity extends Activity {
- privatestaticfinal String TAG = "aidltest";
- private Button btnOk;
- private Button btnCancel;
- @Override
- publicvoid onCreate(Bundle icicle) {
- super.onCreate(icicle);
- setContentView(R.layout.test_service);
- btnOk = (Button)findViewById(R.id.btn_ok);
- btnCancel = (Button)findViewById(R.id.btn_cancel);
- btnOk.setText("Start Service");
- btnCancel.setText("Stop Service");
- btnCancel.setEnabled(false);
- btnOk.setOnClickListener(new OnClickListener() {
- publicvoid onClick(View v) {
- onOkClick();
- }
- });
- btnCancel.setOnClickListener(new OnClickListener() {
- publicvoid onClick(View v) {
- onCancelClick();
- }
- });
- }
- void onOkClick() {
- printf("send intent to start");
- Bundle args = new Bundle();
- Intent intent = new Intent("com.cmcc.demo.IMyService");
- intent.putExtras(args);
- startService(intent);
- //bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
- btnCancel.setEnabled(true);
- }
- void onCancelClick() {
- printf("send intent to stop");
- //unbindService(mConnection);
- Intent intent = new Intent("com.cmcc.demo.IMyService");
- stopService(intent);
- btnCancel.setEnabled(false);
- }
- privatevoid printf(String str) {
- Log.v(TAG, "###################------ " + str + "------");
- }
- ITaskBinder mService;
- private ServiceConnection mConnection = new ServiceConnection() {
- publicvoid onServiceConnected(ComponentName className, IBinder service) {
- mService = ITaskBinder.Stub.asInterface(service);
- try {
- mService.registerCallback(mCallback);
- } catch (RemoteException e) {
- }
- }
- publicvoid onServiceDisconnected(ComponentName className) {
- mService = null;
- }
- };
- private ITaskCallback mCallback = new ITaskCallback.Stub() {
- publicvoid actionPerformed(int id) {
- printf("callback id=" + id);
- }
- };
- }
總結一下aidl的使用
AIDL的建立方法: AIDL語法很簡單,可以用來宣告一個帶一個或多個方法的介面,也可以傳遞引數和返回值。由於遠端呼叫的需要, 這些引數和返回值並不是任何型別.下面是些AIDL支援的資料型別:1. 不需要import宣告的簡單Java程式語言型別(int,boolean等)2. String, CharSequence不需要特殊宣告3. List, Map和Parcelables型別, 這些型別內所包含的資料成員也只能是簡單資料型別, String等其他比支援的型別.((另外: 我沒嘗試Parcelables, 在Eclipse+ADT下編譯不過, 或許以後會有所支援).下面是AIDL語法:// 檔名: SomeClass.aidl // 檔案可以有註釋, 跟java的一樣 // 在package以前的註釋, 將會被忽略. // 函式和變數以前的註釋, 都會被加入到生產java程式碼中. package com.cmcc.demo;// import 引入語句 import com.cmcc.demo.ITaskCallback;interface ITaskBinder {//函式跟java一樣, 可以有0到多個引數 ,可以有一個返回值 boolean isTaskRunning();void stopRunningTask(); //引數可以是另外的一個aidl定義的介面 void registerCallback(ITaskCallback cb);void unregisterCallback(ITaskCallback cb);//引數可以是String, 可以用in表入輸入型別, out表示輸出型別.int getCustomerList(in String branch, out String customerList);}
實現介面時有幾個原則: .丟擲的異常不要返回給呼叫者. 跨程序拋異常處理是不可取的..IPC呼叫是同步的。如果你知道一個IPC服務需要超過幾毫秒的時間才能完成地話,你應該避免在Activity的主執行緒中呼叫。
也就是IPC呼叫會掛起應用程式導致介面失去響應. 這種情況應該考慮單起一個執行緒來處理..不能在AIDL介面中宣告靜態屬性。IPC的呼叫步驟: 1. 宣告一個介面型別的變數,該介面型別在.aidl檔案中定義。2. 實現ServiceConnection。3. 呼叫ApplicationContext.bindService(),並在ServiceConnection實現中進行傳遞.4. 在ServiceConnection.onServiceConnected()實現中,你會接收一個IBinder例項(被呼叫的Service). 呼叫 YourInterfaceName.Stub.asInterface((IBinder)service)將引數轉換為YourInterface型別。5. 呼叫介面中定義的方法。 你總要檢測到DeadObjectException異常,該異常在連線斷開時被丟擲。它只會被遠端方法丟擲。6. 斷開連線,呼叫介面例項中的ApplicationContext.unbindService()