在Andorid平台中,各个组件运行在自己的进程中,他们之间是不能相互访问的,但是在程序之间是不可避免的要传递一些对象,在进程之间相互通信。为了实现进程之间的相互通信,Andorid采用了一种轻量级的实现方式RPC(Remote Procedure Call 远程进程调用)来完成进程之间的通信,并且Android通过接口定义语言(Andorid Interface Definition Language ,AIDL)来生成两个进程之间相互访问的代码,例如,你在Activity里的代码需要访问Service中的一个方法,那么就可以通过这种方式来实现了。
AIDL是Android的一种接口描述语言; 编译器可以通过aidl文件生成一段代码,通过预先定义的接口达到两个进程内部通信进程的目的. 如果需要在一个Activity中, 访问另一个Service中的某个对象, 需要先将对象转化成 AIDL可识别的参数(可能是多个参数), 然后使用AIDL来传递这些参数, 在消息的接收端, 使用这些参数组装成自己需要的对象。
AIDL RPC机制是通过接口来实现的,类似Windows中的COM或者Corba,但他是轻量级的,客户端和被调用实现之间是通过代理模式实现的,代理类和被代理类实现同一个接口Ibinder接口。
远程绑定调用service主要是用来不同进程的信息共享。就比如服务器和客户端,在服务器端设置好一个service提供方法或信息,然后客户端可以直接调用服务器端service提供方法或信息。这里有个前提是客户端必须有和服务器端一份一样的AIDL.
这这里笔者使用的demo,是在上一篇博客<绑定服务调用本地服务中的方法>基础上修改的, 想查看上一篇博客可点击链接: http://www.cnblogs.com/wanghaoyuhappy/p/5293696.html
1. 先来看一下远程服务中的目录结构:
以及另一个应用的目录结构
2. 下面是远程服务中的Service代码:
1 public class ALiPayService extends Service { 2 3 //创建内部人员,继承aidl 4 private class MyBinder extends IService.Stub { 5 public void callMethodInService(String name,int money){ 6 7 serviceInMethod(name,money); 8 } 9 } 10 11 //在绑定服务时调用该方法, 12 //返回了IBinder对象 13 @Override 14 public IBinder onBind(Intent arg0) { 15 return new MyBinder(); 16 } 17 18 @Override 19 public void onCreate() { 20 System.out.println("服务已开启"); 21 super.onCreate(); 22 } 23 24 @Override 25 public void onDestroy() { 26 System.out.println("服务已销毁"); 27 super.onDestroy(); 28 } 29 30 //服务中的方法 31 public void serviceInMethod(String name,int money){ 32 System.out.println(name + "成功存入"+ money); 33 } 34 35 }
与调用本地服务不同的是: 在Service中创建内部类的时候需要继承IService.aidl中的Stub方法,为什么呢?
因为在自动生成的IService.aidl文件中, Stub方法已经继承了IBinder对象并实现了接口.
3. 下面是IService.aidl的代码:
1 package com.example.remoteservice; 2 3 interface IService { 4 void callMethodInService(String name, int money); 5 }
注意: 在普通的接口中, 需要定义访问修饰符为public, 而在aidl文件中不可以定义访问修饰符
新建了一个aidl文件后, Eclipse会在gen目录下自动创建一个IService.java文件, 详细看上面的目录结构
4. 下面是另一个应用程序, 也就是调用者的示例代码:
(1) 首先需要将远程服务中的aidl文件连同所在的包一同复制到自己的工程下
保证自己工程下的aidl文件与远程服务中的aidl文件相同,包括包名
(2) 下面是Activity中的示例代码:
1 public class MainActivity extends Activity { 2 3 @Override 4 protected void onCreate(Bundle savedInstanceState) { 5 super.onCreate(savedInstanceState); 6 setContentView(R.layout.activity_main); 7 } 8 9 private Myconn conn; 10 private IService iService; 11 12 // 与服务建立连接的一个通道 13 private class Myconn implements ServiceConnection { 14 15 @Override 16 public void onServiceConnected(ComponentName name, IBinder service) { 17 // 与远程服务器建立连接 18 iService = IService.Stub.asInterface(service); 19 } 20 21 @Override 22 public void onServiceDisconnected(ComponentName name) { 23 24 } 25 } 26 27 public void start(View view) { 28 // 这个时候需要用隐式意图了 29 Intent intent = new Intent("com.example.remoteservice"); 30 startService(intent); 31 } 32 33 public void bind(View view) { 34 Intent intent = new Intent("com.example.remoteservice"); 35 conn = new Myconn(); 36 bindService(intent, conn, BIND_AUTO_CREATE); 37 } 38 39 // 调用服务中的方法 40 public void call(View view) { 41 try { 42 iService.callMethodInService("张三", 500); 43 } catch (RemoteException e) { 44 e.printStackTrace(); 45 } 46 } 47 48 public void unbind(View view) { 49 if (conn != null) { 50 // 解绑服务 51 unbindService(conn); 52 // 连接的通道置为空,释放资源 53 conn = null; 54 } 55 } 56 57 public void stop(View view) { 58 Intent intent = new Intent("com.example.remoteservice"); 59 stopService(intent); 60 } 61 62 //在用户按返回键时,解绑服务,防止内存泄露 63 @Override 64 public void onBackPressed() { 65 super.onBackPressed(); 66 if (conn != null) { 67 // 解绑服务 68 unbindService(conn); 69 // 连接的通道置为空,释放资源 70 conn = null; 71 } 72 } 73 74 }
关键代码已经用红色标出, 有两点需要注意:
1) 在绑定服务的时候需要用隐式意图了
2) 在连接服务的时候使用的是这句代码: iService = IService.Stub.asInterface(service);
5. 另外下面是Service中清单文件的注册信息:
1 <service android:name="com.example.remoteservice.ALiPayService"> 2 <intent-filter> 3 <action android:name="com.example.remoteservice"/> 4 </intent-filter> 5 </service>
6. 运行效果如图:
OK,搞定了!!!