代码改变世界

Android中使用AIDL时的跨进程回调—Server回调Client

2015-08-28 12:39  指针空间  阅读(1170)  评论(0编辑  收藏  举报

首先建立在server端建立两个aidl文件

ITaskCallback.aidl 用于存放要回调client端的方法

  1. package com.cmcc.demo.server;   
  2.   
  3. interface ITaskCallback {   
  4.     void actionPerformed(int actionId);  
  5. }   

 

ITaskBinder.aidl 用于存放供给client端调用的方法

  1. package com.cmcc.demo.server;   
  2.   
  3. import com.cmcc.demo.server.ITaskCallback;   
  4.   
  5. interface ITaskBinder {   
  6.     boolean isTaskRunning();   
  7.     void stopRunningTask();   
  8.     void registerCallback(ITaskCallback cb);   
  9.     void unregisterCallback(ITaskCallback cb);   
  10. }  

 

接着建立服务端,要实现回调,需要新建RemoteCallbackList对象(一个存储回调对象的列表),通过类似发送广播的形式来实现回调

MyService.java

  1. package com.cmcc.demo.server;   
  2.   
  3. import com.cmcc.demo.server.ITaskBinder;  
  4. import com.cmcc.demo.server.ITaskCallback;  
  5.   
  6. import android.app.Service;   
  7. import android.content.Intent;   
  8. import android.os.IBinder;   
  9. import android.os.RemoteCallbackList;   
  10. import android.os.RemoteException;   
  11. import android.util.Log;   
  12.   
  13. public class MyService extends Service {   
  14.     private static final String TAG = "aidltest";  
  15.   
  16.     @Override   
  17.     public void onCreate() {   
  18.         printf("service create");   
  19.     }  
  20.       
  21.     @Override   
  22.     public void onStart(Intent intent, int startId) {  
  23.         printf("service start id=" + startId);  
  24.         callback(startId);   
  25.     }  
  26.       
  27.     @Override  
  28.     public IBinder onBind(Intent t) {  
  29.         printf("service on bind");  
  30.         return mBinder;   
  31.     }  
  32.       
  33.     @Override  
  34.     public void onDestroy() {   
  35.         printf("service on destroy");   
  36.         super.onDestroy();   
  37.     }  
  38.       
  39.     @Override  
  40.     public boolean onUnbind(Intent intent) {   
  41.         printf("service on unbind");  
  42.         return super.onUnbind(intent);   
  43.     }  
  44.       
  45.     public void onRebind(Intent intent) {   
  46.         printf("service on rebind");  
  47.         super.onRebind(intent);   
  48.     }  
  49.       
  50.     private void printf(String str) {   
  51.         Log.v(TAG, "###################------ " + str + "------");   
  52.     }  
  53.       
  54.     void callback(int val) {   
  55.         final int N = mCallbacks.beginBroadcast();  
  56.         for (int i=0; i<N; i++) {   
  57.             try {  
  58.                 mCallbacks.getBroadcastItem(i).actionPerformed(val);   
  59.             }  
  60.             catch (RemoteException e) {   
  61.                 // The RemoteCallbackList will take care of removing   
  62.                 // the dead object for us.     
  63.             }  
  64.         }  
  65.         mCallbacks.finishBroadcast();  
  66.     }  
  67.       
  68.     private final ITaskBinder.Stub mBinder = new ITaskBinder.Stub() {  
  69.           
  70.         public void stopRunningTask() {  
  71.               
  72.         }  
  73.       
  74.         public boolean isTaskRunning() {   
  75.             return false;   
  76.         }   
  77.           
  78.         public void registerCallback(ITaskCallback cb) {   
  79.             if (cb != null) {   
  80.                 mCallbacks.register(cb);  
  81.             }  
  82.         }  
  83.           
  84.         public void unregisterCallback(ITaskCallback cb) {  
  85.             if(cb != null) {  
  86.                 mCallbacks.unregister(cb);  
  87.             }  
  88.         }  
  89.     };   
  90.       
  91.     final RemoteCallbackList <ITaskCallback>mCallbacks = new RemoteCallbackList <ITaskCallback>();  
  92.   
  93. }   


最后建立客户端,使用aidl,实现回调方法。

MyActivity.java

  1. package com.cmcc.demo;   
  2.   
  3. import android.app.Activity;   
  4. import android.content.ComponentName;   
  5. import android.content.Intent;   
  6. import android.content.ServiceConnection;   
  7. import android.os.Bundle;   
  8. import android.os.IBinder;   
  9. import android.os.RemoteException;   
  10. import android.util.Log;   
  11. import android.view.View;   
  12. import android.view.View.OnClickListener;   
  13. import android.widget.Button;   
  14.   
  15. import com.cmcc.demo.server.*;  
  16.   
  17. public class MyActivity extends Activity {   
  18.   
  19.     private static final String TAG = "aidltest";  
  20.     private Button btnOk;   
  21.     private Button btnCancel;  
  22.   
  23. @Override   
  24. public void onCreate(Bundle icicle) {   
  25.     super.onCreate(icicle);   
  26.     setContentView(R.layout.test_service);   
  27.       
  28.     btnOk = (Button)findViewById(R.id.btn_ok);  
  29.     btnCancel = (Button)findViewById(R.id.btn_cancel);   
  30.     btnOk.setText("Start Service");   
  31.     btnCancel.setText("Stop Service");   
  32.     btnCancel.setEnabled(false);  
  33.       
  34.     btnOk.setOnClickListener(new OnClickListener() {  
  35.             public void onClick(View v) {  
  36.                 onOkClick();  
  37.             }  
  38.         });   
  39.       
  40.     btnCancel.setOnClickListener(new OnClickListener() {  
  41.             public void onClick(View v) {  
  42.                 onCancelClick();  
  43.             }  
  44.         });  
  45.     }   
  46.   
  47.     void onOkClick() {  
  48.         printf("send intent to start");   
  49.         Bundle args = new Bundle();  
  50.         Intent intent = new Intent("com.cmcc.demo.IMyService");  
  51.         intent.putExtras(args);  
  52.         startService(intent);  
  53.         //bindService(intent, mConnection, Context.BIND_AUTO_CREATE);  
  54.         btnCancel.setEnabled(true);  
  55.     }   
  56.       
  57.     void onCancelClick() {   
  58.           
  59.         printf("send intent to stop");  
  60.         //unbindService(mConnection);  
  61.         Intent intent = new Intent("com.cmcc.demo.IMyService");  
  62.         stopService(intent);   
  63.         btnCancel.setEnabled(false);  
  64.     }   
  65.       
  66.     private void printf(String str) {   
  67.         Log.v(TAG, "###################------ " + str + "------");   
  68.     }  
  69.       
  70.     ITaskBinder mService;   
  71.       
  72.     private ServiceConnection mConnection = new ServiceConnection() {   
  73.           
  74.         public void onServiceConnected(ComponentName className, IBinder service) {  
  75.             mService = ITaskBinder.Stub.asInterface(service);   
  76.             try {   
  77.                 mService.registerCallback(mCallback);  
  78.             } catch (RemoteException e) {  
  79.                   
  80.             }  
  81.         }  
  82.           
  83.         public void onServiceDisconnected(ComponentName className) {   
  84.             mService = null;  
  85.         }   
  86.     };   
  87.       
  88.     private ITaskCallback mCallback = new ITaskCallback.Stub() {  
  89.           
  90.         public void actionPerformed(int id) {   
  91.             printf("callback id=" + id);  
  92.         }   
  93.     };   
  94.   
  95. }   


总结一下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); 
} 

实现接口时有几个原则: 
.抛出的异常不要返回给调用者. 跨进程抛异常处理是不可取的. 
. 
.不能在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()