知识点讲解:

在Android中, 每个应用程序都有自己的进程,当需要在不同的进程之间传递对象时,该如何实现呢? 显然, Java中是不支持跨进程内存共享的。因此要传递对象, 需要把对象解析成操作系统能够理解的数据格式, 以达到跨界对象访问的目的。在JavaEE中,采用RMI通过序列化传递对象。在Android中, 则采用AIDL(Android Interface Definition Language:接口定义语言)方式实现。

AIDL是一种接口定义语言,用于约束两个进程间的通讯规则,供编译器生成代码,实现Android设备上的两个进程间通信(IPC)。AIDL的IPC机制和EJB所采用的CORBA很类似,进程之间的通信信息,首先会被转换成AIDL协议消息,然后发送给对方,对方收到AIDL协议消息后再转换成相应的对象。由于进程之间的通信信息需要双向转换,所以android采用代理类在背后实现了信息的双向转换,代理类由android编译器生成,对开发人员来说是透明的。

实现进程通信,一般需要下面四个步骤:

假设A应用需要与B应用进行通信,调用B应用中的download(String path)方法,B应用以Service方式向A应用提供服务。需要下面四个步骤:

1> 在B应用中创建*.aidl文件,aidl文件的定义和接口的定义很相类,如:在cn.itcast.aidl包下创建IDownloadService.aidl文件,内容如下:
package cn.itcast.aidl;
interface IDownloadService {
void download(String path);
}
当完成aidl文件创建后,eclipse会自动在项目的gen目录中同步生成IDownloadService.java接口文件。接口文件中生成一个Stub的抽象类,里面包括aidl定义的方法,还包括一些其它辅助方法。值得关注的是asInterface(IBinder iBinder),它返回接口类型的实例,对于远程服务调用,远程服务返回给客户端的对象为代理对象,客户端在onServiceConnected(ComponentName name, IBinder service)方法引用该对象时不能直接强转成接口类型的实例,而应该使用asInterface(IBinder iBinder)进行类型转换。

编写Aidl文件时,需要注意下面几点:
1.接口名和aidl文件名相同。
2.接口和方法前不用加访问权限修饰符public,private,protected等,也不能用final,static。
3.Aidl默认支持的类型包话java基本类型(int、long、boolean等)和(String、List、Map、CharSequence),使用这些类型时不需要import声明。对于List和Map中的元素类型必须是Aidl支持的类型。如果使用自定义类型作为参数或返回值,自定义类型必须实现Parcelable接口。
4.自定义类型和AIDL生成的其它接口类型在aidl描述文件中,应该显式import,即便在该类和定义的包在同一个包中。
5.在aidl文件中所有非Java基本类型参数必须加上in、out、inout标记,以指明参数是输入参数、输出参数还是输入输出参数。
6.Java原始类型默认的标记为in,不能为其它标记。

2> 在B应用中实现aidl文件生成的接口(本例是IDownloadService),但并非直接实现接口,而是通过继承接口的Stub来实现(Stub抽象类内部实现了aidl接口),并且实现接口方法的代码。内容如下:
public class ServiceBinder extends IDownloadService.Stub {
@Override
public void download(String path) throws RemoteException {
Log.i("DownloadService", path);
}
}

3> 在B应用中创建一个Service(服务),在服务的onBind(Intent intent)方法中返回实现了aidl接口的对象(本例是ServiceBinder)。内容如下:
public class DownloadService extends Service {
private ServiceBinder serviceBinder = new ServiceBinder();
@Override
public IBinder onBind(Intent intent) {
return serviceBinder;
}
public class ServiceBinder extends IDownloadService.Stub {
@Override
public void download(String path) throws RemoteException {
Log.i("DownloadService", path);
}
}
}
其他应用可以通过隐式意图访问服务,意图的动作可以自定义,AndroidManifest.xml配置代码如下:
<service android:name=".DownloadService" >
<intent-filter>
<action android:name="cn.itcast.process.aidl.DownloadService" />
</intent-filter>
</service>


4> 把B应用中aidl文件所在package连同aidl文件一起拷贝到客户端A应用,eclipse会自动在A应用的gen目录中为aidl文件同步生成IDownloadService.java接口文件,接下来就可以在A应用中实现与B应用通信,代码如下:
public class ClientActivity extends Activity {
private IDownloadService downloadService;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
this.bindService(new Intent("cn.itcast.process.aidl.DownloadService"), this.serviceConnection, BIND_AUTO_CREATE);//绑定到服务
}

@Override
protected void onDestroy() {
super.onDestroy();
this.unbindService(serviceConnection);//解除服务
}

private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
downloadService = IDownloadService.Stub.asInterface(service);
try {
downloadService.download("http://www.itcast.cn");
} catch (RemoteException e) {
Log.e("ClientActivity", e.toString());
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
downloadService = null;
}
};

}

代码示例:

提供服务的工程:remoteservice

RemoteService.java:

package cn.itcast.remoteservice;import android.app.IntentService;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;import android.test.IsolatedContext;public class RemoteService extends Service {@Overridepublic IBinder onBind(Intent intent) {return new MyBinder();}private class MyBinder extends IService.Stub {@Overridepublic void callMethodInService() throws RemoteException {sayHelloInService();}}/** * 服务里面的一个方法 */public void sayHelloInService() {System.out.println("hello in service");}@Overridepublic void onCreate() {System.out.println("remote service oncreate");super.onCreate();}}
IService.java:(要将后缀改为.aidl)

package cn.itcast.remoteservice;interface IService { void callMethodInService();}
要在清单文件中Application节点下加入:

<service android:name=".RemoteService" >            <intent-filter >                <action android:name="cn.itcast.remoteservice"/>            </intent-filter></service>

下面就是调用服务方法的工程了callremoteService:

DemoActivity.java:

package cn.itcast.callremote;import cn.itcast.remoteservice.IService;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.view.View;public class DemoActivity extends Activity {IService iService;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);Intent intent = new Intent();intent.setAction("cn.itcast.remoteservice");//通过隐式意图调用服务bindService(intent, new MyConn(), BIND_AUTO_CREATE);}public void click(View view) {try {// 调用了远程服务的方法iService.callMethodInService();} catch (RemoteException e) {// TODO Auto-generated catch blocke.printStackTrace();}}private class MyConn implements ServiceConnection {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {iService = IService.Stub.asInterface(service);}@Overridepublic void onServiceDisconnected(ComponentName name) {// TODO Auto-generated method stub}}}
Src下其中也要有Iservice.aidl,这里就不再粘贴了。


对比式总结流程:

1.要想访问 同一个进程里面的服务的方法 我们需要用到 bindservice();
一 创建一个服务 这个服务里面有一个要被调用的方法.
二 定义一个接口IService , 接口里面的抽象方法 就是去调用service里面的方法
三 定义一个mybinder对象 extends IBinder对象 实现 我们声明的接口IService, 在onbind 方法里面把mybinder返回回去
四 在activity里面 通过bindservice的方法开启服务
五 创建出来一个我们MyConn 实现 ServiceConnection接口 onserviceConnected的方法 这个方法会有一个参数 这个参数就是 MyBinder的对象
六 把mybinder强制类型转化成 IServcie
七 调用IService里面的方法



2.要想访问一个远程服务里的方法 需要用到aidl
一 创建一个服务 这个服务里面有一个要被调用的方法.
二 定义一个接口IService , 接口里面的抽象方法 就是去调用service里面的方法 把.java的后缀名改成aidl 把接口里面定义的访问权限的修饰符都给删除
三 定义一个mybinder对象 extends IService.Stub, 在onbind 方法里面把mybinder返回回去
四 在activity里面 通过bindservice的方法开启服务
五 创建出来一个我们MyConn 实现 ServiceConnection接口 onserviceConnected的方法 这个方法会有一个参数 这个参数就是 MyBinder的对象
六 IService = IService.Stub.asInterface(myBinder)
七 调用IService的方法

更多相关文章

  1. Android(安卓)源码详解:View的事件分发机制
  2. Android-动画实现原理
  3. Android的一个技巧
  4. android解析xml文件的方式(其三)
  5. Android(安卓)ListView那些事
  6. Android学习笔记(7)---单元测试与日志输出
  7. Android(安卓)RefBase类(sp,wp)
  8. Android中跨进程通信的IPC机制(Binder框架)
  9. Android(安卓)AIDL 实现浅析

随机推荐

  1. Android布局优化(一),Android渲染机制
  2. 2011.09.22——— android ViewStub的简
  3. Android监听来电和去电
  4. android 不自动弹出虚拟键盘
  5. Chrome V8 引擎移植到 Android
  6. Failed to sync vcpu reg
  7. android 数据库 备份还原
  8. Android RelativeLayout 实现顶部左中右
  9. android framework
  10. android EditText 去除边框