Android 进程间通信(AIDL)使用详解

远程Service与Activity的交互(AIDL的应用)

首先我们先上一个通俗的情景:在应用1中Activity绑定了一个Service,并且设置了一些值,此时我们想在应用2中调用该service并且想得到该值应该怎么做?我们都知道每个应用程序都运行在各自的进程中,并且android平台是不允许不同进程间进行直接的对象数据等传递的。如果必须进行跨进程之间的数据传递,那么我们就应该使用AIDL(Android Interface Definition Language)。

AIDL只支持方法,不能定义静态成员,并且方法也不能有类似public等的修饰符;AIDL运行方法有任何类型的参数和返回值,在java的类型中,以下的类型使用时不需要导入包(import),基本数据类型、String、Map、List.当然为了避免出错,建议只要使用了,就导入包。

使用AIDL的步骤:

       服务端(提供服务):

        第1步:定义一个*.aidl文件,该文件里是符合aidl语言规范的接口定义,里面定义了外部应用可以访问的方法。当我们保存该文件的时候,eclipse会自动为我们在gen文件夹下生成一个相应的java接口文件。如:

[java]  view plain  copy
 print ?
  1. package com.android.macdroid;  
  2. interface IPerson {   
  3.     void setValue(String name);  
  4.     String getValue();   
  5. }  

    第2步:实现AIDL文件生成的JAVA接口Stub

[java]  view plain  copy
 print ?
  1. class Person extends IPerson.Stub {  
  2.     private String name;  
  3.      
  4.     @Override  
  5.     public void setValue(String name) throws RemoteException {  
  6.        this.name = name ;  
  7.     }  
  8.   
  9.     @Override  
  10.     public String getValue() throws RemoteException {  
  11.         return name;  
  12.     }  
  13.       
  14. }  

     第3步:定义一个自己的service,    并将其注册到androidManifest.xml文件中,例如:

[java]  view plain  copy
 print ?
  1. public class ServiceC extends Service {    
  2.     private Stub iPerson = new Person();    
  3.     @Override    
  4.     public IBinder onBind(Intent arg0) {    
  5.         Log.i("service""onBind...");    
  6.         return iPerson;    
  7.     }    
  8. }   
[html]  view plain  copy
 print ?
  1. <service android:name="com.android.macdroid.ServiceC" >  
  2.            <intent-filter >  
  3.                <action android:name="forServiceAidl" > </action>  
  4.            </intent-filter>  
  5.        </service>  

       我们都知道,在实现自己的service时,为了其他应用可以通过bindService来和我们的service进行交互,我们都要实现service中的onBind()方法,并且返回一个继承了Binder的内部类;在这里,eclipse自动为我们生成的RemoteServiceInterface.java中有一个实现了Binder的内部类,RemoteServiceInterface.Stub。AIDL要求我们,在这里不能再直接去实现Binder类了,而是去实现,AIDL提供给我们的Stub类。 实现stub类的同时,AIDL还要求我们同时实现我们在接口中定义的各种服务的具体实现。至此为止,我们的服务端已经和我们的aidl文件绑定到一起了哦。

同一个应用中的Activity为该Service中赋值:

[java]  view plain  copy
 print ?
  1. package com.android.macdroid;  
  2.   
  3. import android.app.Activity;  
  4. import android.app.Service;  
  5. import android.content.ComponentName;  
  6. import android.content.DialogInterface;  
  7. import android.view.View;  
  8. import android.view.View.OnClickListener;  
  9. import android.content.Intent;  
  10. import android.content.ServiceConnection;  
  11. import android.os.Bundle;  
  12. import android.os.IBinder;  
  13. import android.os.RemoteException;  
  14. import android.widget.Button;  
  15. import android.widget.Toast;  
  16. import com.android.macdroid.IPerson;  
  17.   
  18. public class AIDLTestActivity extends Activity  {  
  19.   
  20.     private IPerson iPerson;  
  21.     private Button bindBtn, unbindBtn;   
  22.   
  23.     private ServiceConnection conn = new ServiceConnection() {  
  24.   
  25.         // 断开连接时调用  
  26.         @Override  
  27.         public void onServiceDisconnected(ComponentName arg0) {  
  28.         }  
  29.   
  30.         // 连接时调用  
  31.         @Override  
  32.         public void onServiceConnected(ComponentName arg0, IBinder binder) {  
  33.             iPerson = IPerson.Stub.asInterface(binder);  
  34.             if (iPerson != null) {  
  35.                 try {  
  36.                     iPerson.setValue("Service AIDL");  
  37.                     Toast.makeText(AIDLTestActivity.this"赋值成功!",  
  38.                             Toast.LENGTH_LONG).show();  
  39.                 } catch (RemoteException e) {  
  40.                     e.printStackTrace();  
  41.                     Toast.makeText(AIDLTestActivity.this"赋值失败!",  
  42.                             Toast.LENGTH_LONG).show();  
  43.                 }  
  44.             }  
  45.         }  
  46.     };  
  47.   
  48.     @Override  
  49.     public void onCreate(Bundle savedInstanceState) {  
  50.         super.onCreate(savedInstanceState);  
  51.         setContentView(R.layout.main);  
  52.         bindBtn = (Button) findViewById(R.id.bindBtn);  
  53.         unbindBtn = (Button) findViewById(R.id.unbindBtn);  
  54.         bindBtn.setOnClickListener((android.view.View.OnClickListener) listener);  
  55.         bindBtn.setOnClickListener(listener);  
  56.         unbindBtn.setOnClickListener(listener);  
  57.     }  
  58.     private OnClickListener listener = new OnClickListener() {    
  59.   
  60.         @Override  
  61.         public void onClick(View v) {  
  62.             // TODO Auto-generated method stub  
  63.               switch (v.getId()) {    
  64.                 case R.id.bindBtn:    
  65.                     //本应用中需要在manifest中配置RemoteService    
  66.                     bindService(new Intent("forServiceAidl"), conn, Service.BIND_AUTO_CREATE);    
  67.                     break;    
  68.                 case R.id.unbindBtn:    
  69.                     unbindService(conn);    
  70.                     break;    
  71.                 default:    
  72.                     break;    
  73.                 }    
  74.         }  
  75.   
  76.     };   
  77.   
  78. }  




客户端:
       
第1步:客户端要想使用该服务,肯定要先知道我们的服务在aidl文件中到底对外提供了什么服务,对吧?所以,第一步,我们要做的就是,将aidl文件拷贝一份到客户端的程序中(这里一定要注意,包路径要和服务端的保持一致哦,例如服务端为cn.com.chenzheng_java.remote.a.aidl,那么在客户端这边也应该是这个路径)

      第2步:我们都知道,想要和service交互,我们要通过bindService方法,该方法中有一个ServiceConnection类型的参数。而我们的主要代码便是在该接口的实现中。

      
第3步:在ServiceConnection实现类的onServiceConnected(ComponentName name, IBinder service)方法中通过类似remoteServiceInterface = RemoteServiceInterface.Stub.asInterface(service);方式就可以获得远程服务端提供的服务的实例,然后我们就可以通过remoteServiceInterface 对象调用接口中提供的方法进行交互了。(这里的关键是通过*.Stub.asInterface(service);方法获取一个aidl接口的实例哦)

       我们前面在服务端中说过了,必须提供一个intent-filter来匹配请求是否合法,所以我们在客户端访问服务的时候,还必须传递包含了匹配action的Intent哦。

客户端中使用服务端中的service范例:

[java]  view plain  copy
 print ?
  1. private ServiceConnection conn = new ServiceConnection() {    
  2.      @Override    
  3.      public void onServiceDisconnected(ComponentName arg0) {    
  4.      }    
  5.      //因为有可能有多个应用同时进行RPC操作,所以同步该方法    
  6.      @Override    
  7.      public synchronized void onServiceConnected(ComponentName arg0, IBinder binder) {    
  8.          //获得IPerson接口    
  9.          person = IPerson.Stub.asInterface(binder);    
  10.          if(person != null){    
  11.              try {    
  12.                  //RPC方法调用    
  13.                  String name = person.getValue();    
  14.                  Toast.makeText(DemoAIDLActivity.this"远程进程调用成功!值为 : "+name, Toast.LENGTH_LONG).show();    
  15.              } catch (RemoteException e) {    
  16.                  e.printStackTrace();      
  17.                  Toast.makeText(DemoAIDLActivity.this"远程进程调用失败! ", Toast.LENGTH_LONG).show();    
  18.              }    
  19.          }    
  20.      }  
  21.  };    
  22.      
  23.  @Override    
  24.  public void onCreate(Bundle savedInstanceState) {    
  25.      super.onCreate(savedInstanceState);    
  26.      setContentView(R.layout.main);    
  27.      btn = (Button)findViewById(R.id.btn);    
  28.      btn.setOnClickListener(new OnClickListener() {    
  29.          @Override    
  30.          public void onClick(View arg0) {    
  31.              //该应用中不需要在manifest中配置RemoteService    
  32.              bindService(new Intent("forServiceAidl"), conn, Service.BIND_AUTO_CREATE);    
  33.          }    
  34.      });    
  35.  }    


参考博客:Android Service学习之AIDL, Parcelable和远程服务  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值