aidl详解:同一APK内,不同apk间的activty与service通信

来源:互联网 发布:17173lol数据库 编辑:程序博客网 时间:2024/05/22 00:08

1.什么是aidl:aidl是 Android Interface definition language的缩写,一看就明白,它是一种android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口
icp:interprocess communication :内部进程通信

 

2.既然aidl可以定义并实现进程通信,那么我们怎么使用它呢?文档/android-sdk/docs/guide/developing/tools/aidl.html中对步骤作了详细描述:

--1.Create your .aidl file - This file defines an interface (YourInterface.aidl) that defines the methods and fields available to a client. 
创建你的aidl文件,我在后面给出了一个例子,它的aidl文件定义如下:写法跟java代码类似,但是这里有一点值得注意的就是它可以引用其它aidl文件中定义的接口,但是不能够引用你的java类文件中定义的接口

[java] view plaincopy
  1. package com.cao.android.demos.binder.aidl;    
  2. import com.cao.android.demos.binder.aidl.AIDLActivity;  
  3. interface AIDLService {     
  4.     void registerTestCall(AIDLActivity cb);     
  5.     void invokCallBack();  
  6. }    

--2.Add the .aidl file to your makefile - (the ADT Plugin for Eclipse manages this for you). Android includes the compiler, called AIDL, in the tools/ directory. 
编译你的aidl文件,这个只要是在eclipse中开发,你的adt插件会像资源文件一样把aidl文件编译成java代码生成在gen文件夹下,不用手动去编译:编译生成AIDLService.java如我例子中代码


--3.Implement your interface methods - The AIDL compiler creates an interface in the Java programming language from your AIDL interface. This interface has an inner abstract class named Stub that inherits the interface (and implements a few additional methods necessary for the IPC call). You must create a class that extends YourInterface.Stub and implements the methods you declared in your .aidl file. 
实现你定义aidl接口中的内部抽象类Stub,public static abstract class Stub extends android.os.Binder implements com.cao.android.demos.binder.aidl.AIDLService
Stub类继承了Binder,并继承我们在aidl文件中定义的接口,我们需要实现接口方法,下面是我在例子中实现的Stub类:
 

[java] view plaincopy
  1. private final AIDLService.Stub mBinder = new AIDLService.Stub() {  
  2.   
  3.     @Override  
  4.     public void invokCallBack() throws RemoteException {  
  5.         Log("AIDLService.invokCallBack");  
  6.         Rect1 rect = new Rect1();  
  7.         rect.bottom=-1;  
  8.         rect.left=-1;  
  9.         rect.right=1;  
  10.         rect.top=1;  
  11.         callback.performAction(rect);  
  12.     }  
  13.   
  14.   
  15.     @Override  
  16.     public void registerTestCall(AIDLActivity cb) throws RemoteException {  
  17.         Log("AIDLService.registerTestCall");  
  18.         callback = cb;  
  19.     }  
  20. };  

Stub翻译成中文是存根的意思,注意Stub对象是在被调用端进程,也就是服务端进程,至此,服务端aidl服务端得编码完成了。

--4.Expose your interface to clients - If you're writing a service, you should extend Service and override Service.onBind(Intent) to return an instance of your class that implements your interface. 
第四步告诉你怎么在客户端如何调用服务端得aidl描述的接口对象,doc只告诉我们需要实现Service.onBind(Intent)方法,该方法会返回一个IBinder对象到客户端,绑定服务时不是需要一个ServiceConnection对象么,在没有了解aidl用法前一直不知道它是什么作用,其实他就是用来在客户端绑定service时接收service返回的IBinder对象的:

[java] view plaincopy
  1. AIDLService mService;  
  2. private ServiceConnection mConnection = new ServiceConnection() {  
  3.     public void onServiceConnected(ComponentName className, IBinder service) {  
  4.         Log("connect service");  
  5.         mService = AIDLService.Stub.asInterface(service);  
  6.         try {  
  7.             mService.registerTestCall(mCallback);  
  8.         } catch (RemoteException e) {  
  9.   
  10.         }  
  11.     }  
  12.   
  13.   
  14.     public void onServiceDisconnected(ComponentName className) {  
  15.         Log("disconnect service");  
  16.         mService = null;  
  17.     }  
  18. };  

 

mService就是AIDLService对象,具体可以看我后面提供的示例代码,需要注意在客户端需要存一个服务端实现了的aidl接口描述文件,但是客户端只是使用该aidl接口,不需要实现它的Stub类,获取服务端得aidl对象后mService = AIDLService.Stub.asInterface(service);,就可以在客户端使用它了,对mService对象方法的调用不是在客户端执行,而是在服务端执行。

4.aidl中使用java类,需要实现Parcelable接口,并且在定义类相同包下面对类进行声明:

上面我定义了Rect1类
之后你就可以在aidl接口中对该类进行使用了
package com.cao.android.demos.binder.aidl;  
import com.cao.android.demos.binder.aidl.Rect1;
interface AIDLActivity {   
    void performAction(in Rect1 rect);   
}  
注意in/out的说明,我这里使用了in表示输入参数,out没有试过,为什么使用in/out暂时没有做深入研究。

5.aidl使用完整示例,为了清除说明aidl使用,我这里写了一个例子,例子参考了博客:

http://blog.csdn.net/saintswordsman/archive/2010/01/04/5130947.aspx

作出说明

例子实现了一个AIDLTestActivity,AIDLTestActivity通过bindservice绑定一个服务AIDLTestService,通过并获取AIDLTestActivity的一个aidl对象AIDLService,该对象提供两个方法,一个是registerTestCall注册一个aidl对象,通过该方法,AIDLTestActivity把本身实现的一个aidl对象AIDLActivity传到AIDLTestService,在AIDLTestService通过操作AIDLActivity这个aidl远端对象代理,使AIDLTestActivity弹出一个toast,完整例子见我上传的资源:

http://download.csdn.net/detail/tiananma0607/9248037


两个apk之间数据通信(AIDL通信)

研究过framwork的都知道,有一种通信叫跨进程通信---binder通信。每个模块都离不开binder。

那么两个apk直接通信用什么方法呢?可以用跨进程的服务和AIDL来实现。

前段时间,我想实现两个一个apk调用另一个apk的方法时,在网上搜也没搜到完整的例子。APIDemos里面的例子也不完整。

所就整理出完整的例子供一起学习。

服务端:

布局:

[html] view plaincopyprint?
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent" >  
  5.   
  6.     <Button  
  7.         android:id="@+id/button"  
  8.         android:layout_width="wrap_content"  
  9.         android:layout_height="wrap_content"  
  10.         android:text="@string/hello_world"  
  11.         tools:context=".MainActivity" />  
  12.   
  13. </LinearLayout>  



Activity1:

[java] view plaincopyprint?
  1. package com.example.server;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. public class ServerActiviy extends Activity {  
  6.   
  7.     @Override  
  8.     public void onCreate(Bundle savedInstanceState) {  
  9.         super.onCreate(savedInstanceState);  
  10.         setContentView(R.layout.activity_main);  
  11.     }  
  12. }  


AIDL接口:

[java] view plaincopyprint?
  1. package com.example.server;  
  2.   
  3. interface IAIDLService {  
  4.     int getId();  
  5. }  



实现AIDL接口:


[java] view plaincopyprint?
  1. package com.example.server;  
  2.   
  3. import com.example.server.IAIDLService;  
  4. import android.app.Service;  
  5. import android.content.Intent;  
  6. import android.os.IBinder;  
  7. import android.os.RemoteException;  
  8.   
  9. public class AIDLService extends Service {  
  10.     @Override  
  11.     public IBinder onBind(Intent intent) {  
  12.         return new ImplAIDLService(); //这个返回值需要一个服务对象。  
  13.     }  
  14.       
  15.     public class ImplAIDLService extends IAIDLService.Stub{  
  16.         @Override  
  17.         public int getId() throws RemoteException {  
  18.             return 123;  
  19.         }  
  20.     }  
  21. }  




客户端:

布局:

[html] view plaincopyprint?
  1. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     package="com.example.client"  
  3.     android:versionCode="1"  
  4.     android:versionName="1.0" >  
  5.   
  6.     <uses-sdk  
  7.         android:minSdkVersion="8"  
  8.         android:targetSdkVersion="15" />  
  9.   
  10.     <application  
  11.         android:icon="@drawable/ic_launcher"  
  12.         android:label="@string/app_name"  
  13.         android:theme="@style/AppTheme" >  
  14.         <activity  
  15.             android:name="com.example.client.MainActivity"  
  16.             android:label="@string/title_activity_main" >  
  17.             <intent-filter>  
  18.                 <action android:name="android.intent.action.MAIN" />  
  19.                 <category android:name="android.intent.category.LAUNCHER" />  
  20.             </intent-filter>  
  21.         </activity>  
  22.     </application>  
  23.   
  24. </manifest>  


Activity :

[java] view plaincopyprint?
  1. package com.example.client;  
  2. import android.app.Activity;  
  3. import android.content.ComponentName;  
  4. import android.content.Context;  
  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.example.client.R;  
  16. import com.example.server.IAIDLService;  
  17.   
  18.   
  19. public class MainActivity extends Activity {  
  20.     private final String TAG = "MMIAudio";  
  21.     Button button =null;  
  22.     private boolean start = false;  
  23.       
  24.     private boolean isBound;    
  25.     private IAIDLService boundService = null;  
  26.       
  27.     @Override  
  28.     public void onCreate(Bundle savedInstanceState) {  
  29.         super.onCreate(savedInstanceState);  
  30.         setContentView(R.layout.activity_main);  
  31.         init();  
  32.         bindService();  
  33.         button.setText(" 点击试试看 ");  
  34.     }  
  35.       
  36.     public void init(){  
  37.         button = (Button)this.findViewById(R.id.button);  
  38.         button.setOnClickListener(new OnClickListener(){  
  39.             @Override  
  40.             public void onClick(View v) {  
  41.                 int count = 0;  
  42.                 if(start){  
  43.                     try {  
  44.                         count = boundService.getId();  
  45.                     } catch (RemoteException e) {  
  46.                         e.printStackTrace();  
  47.                     }  
  48.                     Log.e(TAG, "-->> count = " + count);  
  49.                     button.setText("id = " + count);  
  50.                     unbindService();  
  51.                     start = false;  
  52.                 }else{  
  53.                     bindService();  
  54.                     start = true;  
  55.                     button.setText(" 点击获取 ");  
  56.                 }  
  57.             }  
  58.         });  
  59.     }  
  60.   
  61.     private void bindService() {    
  62.         Intent i = new Intent("com.example.server.IAIDLService");    
  63.         bindService(i, connection, Context.BIND_AUTO_CREATE);    
  64.         isBound = true;    
  65.     }    
  66.     
  67.     private void unbindService() {    
  68.         if (boundService != null) {    
  69.             try {    
  70.                 Log.e(TAG,"_boundService.getId() = "+ boundService.getId());    
  71.             } catch (RemoteException e) {    
  72.                 e.printStackTrace();    
  73.             }    
  74.         }    
  75.     
  76.         if (isBound) {    
  77.             unbindService(connection);    
  78.             isBound = false;    
  79.         }    
  80.     }    
  81.       
  82.     private ServiceConnection connection = new ServiceConnection() {    
  83.         public void onServiceConnected(ComponentName className, IBinder service) {    
  84.             boundService = IAIDLService.Stub.asInterface(service);    
  85.             Log.e(TAG, "-->> onServiceConnected(),  boundService = " + boundService);    
  86.         }    
  87.     
  88.         public void onServiceDisconnected(ComponentName className) {    
  89.             boundService = null;    
  90.             Log.e(TAG, "-->> onServiceDisconnected()");    
  91.         }    
  92.     };    
  93. }  


AIDL接口(和服务端的接口一模一样,包名也必须相同,不论这个服务接口定义在哪里,只要包名和类名一样,都指的是同一个):

[java] view plaincopyprint?
  1. package com.example.server;  
  2.   
  3. interface IAIDLService {  
  4.     int getId();  
  5. }  

网上有在写客户端的时候,把服务端的gen目录下的 包和文件原封不动拷贝到客户端。其实和在客户端创建一模一样的AIDL接口是一样的道理。

以上内容网上转载,实际例程在文章第一部分例程基础上修改

测试工程详见地址,http://download.csdn.net/detail/tiananma0607/9248057


0 0
原创粉丝点击