AIDL和Service实现两进程通信:
AIDL(AndroidInterfaceDefinitionLanguage)是一种接口定义语言,用于生成代码允许Android设备上的两个进程间进程通信(IPC).
如果你需要编写一个进程(比如Activity)访问另一个进程(比如Services)的对象的方法代码,你可以使用AIDL自动生成代码而不用自己配置大量的参数.
AIDLIPC基于接口机制,类似COM,Corba,且更加轻量化.它使用一个代理来在客户和实现间传递值.
使用AIDL实现进程通信可分为五个步骤:
一.创建ISimpleRemoteService.aidl文件
packagecom.teleca.ServiceSample;
interfaceISimpleRemoteService
{
voidaddCommands(Stringcmd);
booleanisBusy();
}
利用aidl.exe生成接口文件.若你的IDE安装了ADT,将会在gen目录或src相应包中自动根据描述文件生成同名接口文件.否则请手动:
命令行:
adilpath\SomeService.adil<CR>
注意:
1.自定义类在aidl描述文件中,即便在同一个包中,也要显式import.
2.在aidl文件中所有非Java原始类型参数必须加上标记:in,out,inout.
3.Java原始类型默认为in,且不能为其它.
4.Java原始类型包括为java.lang,java,util包中包括的类.
5.接口名同aidl文件名.
6.接口前不用加访问权限修饰符public,private,protected等,也不能用final,static.
接口文件分析:
接口中生成一个Stub的抽象类,里面包括aidl定义的方法.还包括一些其它辅助方法.值得关注的是asInterface(IBinderiBinder),它返回接口的实例.
二.实现接口
接口的实现需继承接口.Stub.并实现Stub类的方法.
下面给出一个使用匿名方式实现的例子.
privatefinalISimpleRemoteService.Stubbinder=newISimpleRemoteService.Stub()
{
publicvoidaddCommands(Stringcmd)
{
SimpleRemoteService.this.addCmd(cmd);
}
publicbooleanisBusy()
{
returnSimpleRemoteService.this.isBusy();
}
};
注意:
1.没有异常会正常返回
2.RPC通常比较耗时且是异步的,因此应该在线程中调用RPC服务.
3.只支持方法,不支持静态字段.
三.暴露接口给客户
客户要服务,当然要知道在哪有服务.通常一台服务器可能提供不止一个服务.我们这里只有一个服务.
暴露服务必须继承Service.并实现onBind()方法.
@Override
publicIBinderonBind(Intentintent){
//TODOAuto-generatedmethodstub
returnbinder;
}
注意我们这里可以根据intent来返回不同的服务。
四.使用打包传送参数
如果在接口定义文件中使用了默认允许的类型(基本类型,String,CharSequence,List和Map),这些类型都将被自动处理。如果使用了其他的类型,那么该类型必须实现打包功能(Parcelable接口),而且需要创建一个aidl文件声明它是可打包类。
可分为如下5个步骤:
4.1实现Parcelable接口
4.2实现publicvoidwriteToParcel(Parcelout)方法
4.3实现publicvoidreadFromParcel(Parcelin)方法
4.4添加一个静态字段CREATOR到实现Parcelable.Creator接口的类中
4.5创建一个aidl文件声明你的可打包的类
示例:
Rect.java文件
importandroid.os.Parcel;
importandroid.os.Parcelable;
publicfinalclassRectimplementsParcelable{
publicintleft;
publicinttop;
publicintright;
publicintbottom;
publicstaticfinalParcelable.Creator<Rect>CREATOR=newParcelable.Creator<Rect>(){
publicRectcreateFromParcel(Parcelin){
returnnewRect(in);
}
publicRect[]newArray(intsize){
returnnewRect[size];
}
};
publicRect(){
}
privateRect(Parcelin){
readFromParcel(in);
}
publicvoidwriteToParcel(Parcelout){
out.writeInt(left);
out.writeInt(top);
out.writeInt(right);
out.writeInt(bottom);
}
publicvoidreadFromParcel(Parcelin){
left=in.readInt();
top=in.readInt();
right=in.readInt();
bottom=in.readInt();
}
}
Rect.aidl文件
packageandroid.graphics;
parcelableRect;
五.调用IPC方法
调用IPC方法还有6个步骤:
5.1声明aidl定义的接口类型引用
5.2实现ServiceConnection
5.3调用Context.bindService(),传入ServiceConnection的实现
5.4在你的ServiceConnection.onServiceConnected(),你将得到一个IBinder实例(service).
调用YourInterfaceName.Stub.asInterface((IBinder)service)强制转换YourInterface类型.
5.5调用接口定义的方法.你应该始终小心DeadObjectException异常,当连接不成功或中断它就会抛出,这也是远程对象唯一的一个异常.
5.6断开连接,调用Context.unbindService().
注意:现在关于如何让AIDL定义生成的接口在客服端可见并没有发现完美的方法。
现在我的做法是把AIDL定义生成的接口,拷贝到客服端的工程中。并且让客服端打包时把AIDL定义生成的接口也打包进去。
我尝试过只用AIDL定义生成的接口来编译客户端程序,并不它打包进去。但是客服端根本无法找到服务器端AIDL文件定义生成的接口。
实例1:
服务器端:
文件ISimpleRemoteService.aidl
packagecom.teleca.ServiceSample;
interfaceISimpleRemoteService
{
voidaddCommands(Stringcmd);
booleanisBusy();
}
文件SimpleRemoteService.java
packagecom.teleca.ServiceSample;
importandroid.app.Service;
importandroid.content.Intent;
importandroid.os.IBinder;
importandroid.util.Log;
publicclassSimpleRemoteServiceextendsServiceimplementsRunnable{
privatefinalISimpleRemoteService.Stubbinder=newISimpleRemoteService.Stub()
{
publicvoidaddCommands(Stringcmd)
{
SimpleRemoteService.this.addCmd(cmd);
}
publicbooleanisBusy()
{
returnSimpleRemoteService.this.isBusy();
}
};
Stringtag="hubin";
@Override
publicvoidonCreate(){
Log.i(tag,"oncreate");
StartThread();
}
@Override
publicvoidonDestroy(){
blRun=false;
Log.i(tag,"OnDestory");
}
publicvoidStartThread()
{
if(blRun==false)
{
Threadt=newThread(this);
t.start();
}
}
@Override
publicIBinderonBind(Intentintent){
//TODOAuto-generatedmethodstub
returnbinder;
}
booleanblRun=false;
finalstaticintkSleepTime=5;
finalStringcmdPool[]=newString[10];
intcmdStartCursor=-1;
intcmdEndCursor=-1;
publicvoidrun()
{
blRun=true;
while(blRun)
{
if(cmdStartCursor!=cmdEndCursor)
{
cmdStartCursor=(cmdStartCursor+1)%cmdPool.length;
Log.i(tag,"run:"+cmdPool[cmdStartCursor]);
}
try{
Thread.sleep(kSleepTime);
}catch(InterruptedExceptione)
{
Log.e(tag,"InterruptedException",e);
}
}
}
voidaddCmd(Stringcmd)
{
if((cmdEndCursor+1)%cmdPool.length!=cmdStartCursor)
{
cmdEndCursor++;
cmdEndCursor=cmdEndCursor%cmdPool.length;
cmdPool[cmdEndCursor]=cmd;
}
}
booleanisBusy()
{
returncmdEndCursor!=cmdStartCursor;
}
}
文件AndroidManifest.xml
<?xmlversion="1.0"encoding="utf-8"?>
<manifestxmlns:android="http://schemas.android.com/apk/res/android"
package="com.teleca.ServiceSample"
android:versionCode="1"
android:versionName="1.0">
<applicationandroid:icon="@drawable/icon"android:label="@string/app_name">
<serviceandroid:name="SimpleRemoteService"android:process=":remote">
<intent-filter>
<actionandroid:name="com.teleca.action.STARTSERVICE"/>
</intent-filter>
</service>
</application>
<uses-sdkandroid:minSdkVersion="7"/>
</manifest>
客服端Hello.java
packagecom.teleca;
importandroid.app.Activity;
importandroid.content.ComponentName;
importandroid.content.Context;
importandroid.content.Intent;
importandroid.content.ServiceConnection;
importandroid.net.Uri;
importandroid.os.Bundle;
importandroid.os.IBinder;
importandroid.os.RemoteException;
importandroid.util.Log;
importandroid.view.View;
importandroid.view.View.OnClickListener;
importandroid.widget.Button;
importcom.teleca.ServiceSample.*;
publicclassHelloextendsActivity{
finalstaticStringtag="hubin";
/**Calledwhentheactivityisfirstcreated.*/
@Override
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Buttonbutton1=(Button)findViewById(R.id.Button01);
OnClickListenerlistener1=newOnClickListener(){
@Override
publicvoidonClick(Viewv){
doBindService();
}
};
button1.setOnClickListener(listener1);
Buttonbutton2=(Button)findViewById(R.id.Button02);
OnClickListenerlistener2=newOnClickListener(){
@Override
publicvoidonClick(Viewv){
doUnbindService();
}
};
button2.setOnClickListener(listener2);
Buttonbutton3=(Button)findViewById(R.id.Button03);
OnClickListenerlistener3=newOnClickListener(){
@Override
publicvoidonClick(Viewv){
if(mBoundService==null)
{
Log.i(tag,"theServicehasnotbind!Pleasebindtheservicefirst");
return;
}
Stringcmd="Hello:"+System.currentTimeMillis()%100;
try{
mBoundService.addCommands(cmd);
booleanres=mBoundService.isBusy();
Log.i(tag,"isBusy:"+res);
}catch(RemoteExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
};
button3.setOnClickListener(listener3);
}
privateISimpleRemoteServicemBoundService;
privateServiceConnectionmConnection=newServiceConnection(){
publicvoidonServiceConnected(ComponentNameclassName,IBinderiservice){
mBoundService=ISimpleRemoteService.Stub.asInterface(iservice);
}
publicvoidonServiceDisconnected(ComponentNameclassName){
mBoundService=null;
}
};
booleanmIsBound=true;
voiddoBindService(){
Intentintent=newIntent("com.teleca.action.STARTSERVICE");
bindService(intent,mConnection,Context.BIND_AUTO_CREATE);
mIsBound=true;
}
voiddoUnbindService(){
if(mIsBound){
//Detachourexistingconnection.
unbindService(mConnection);
mIsBound=false;
}
}
@Override
protectedvoidonDestroy(){
super.onDestroy();
doUnbindService();
}
}
分享到:
相关推荐
实现Activity与Service进程间通信 , 不同程序间通讯
代码中包含两个应用程序,两者之间通信采用aidl方案实现 使用方法:将下载下来的图片后缀名改为.zip,再解压即可得到源代码
Android使用AIDL实现进程间通信
为何要开启多进程?主要有两种情况: 一、一个应用由于自身需要采用多进程模式来实现。比如播放器之类,如果仅仅在service中运行会影响主线程的响应速度,很可能会造成ANR;...2、两个进程之间使用AIDL进行通信
AIDL_SERVICE进程间通信(服务器、客户端源码)
通过aidl,实现客户端调用服务端的service的功能。。。
AIDL是Android接口定义语言,它可以用于让某个Service与多个应用程序组件之间进行跨进程通信,从而可以实现多个应用程序共享同一个Service的功能。 实现步骤 例:用 A程序去访问 B程序的MyService.java服务 在B中...
AIDL进程间通讯,包含两个model(aidlClient和aidlService)
通过使用AIDL进程间通信方式,由A.apk 传递参数到B.apk中。实现两个apk之间的数据交互。
使用AIDL实现进程间通信 两个工程即两个APP,实现数据共享 APP1中有个service 不停的对某一个数进行++操作, APP2通过AIDL 获取APP1的Service中的这个值(通过回调) 当然要使用AIDLAPP1中也要做相应处理
Android安卓AIDL进程间通信Service简单例子,分为客户端和服务端代码,一看就会,一看就懂,核心还是IBinder.
Aidl进程间通信简单封装了下,AIDL和Service作为一个library,其他3个app调用,实现3个app共享一个服务,3个中任意app打开即可开启服务,其他两个app共用
AIDL概述:AIDL是一个缩写,全称是Android ...接下来我写了两个demo(AildeService和AidleClient),他们之间通过AIDL方式实现两个进程之间互相通信。详细介绍见简书网址http://www.jianshu.com/p/4839abb93b47
aidl远程服务客户端和服务端, aidl remoteService 进程间通信
本文简单的实现Aidl在Service与Activity的使用,并提供可运行的实例代码 http://blog.csdn.net/kutear
文件包含两个工程,Client和Server,通过aidl实现客户端和服务端之间的通信。 服务端和客户端都创建一个aidl文件,定义接口。 服务端通过service将接口暴露给客户端,客户端绑定服务。 解压即可运行。
进程间通信涉及到客户端和服务端, 肯定有绑定服务的过程, 所以要阅读一下Android Service相关的知识, 跨进程通信的媒介aidl文件,我们也必须要了解怎么创建的,有什么规则,所以请先阅读一下Android AIDL使用这篇...
aidl跨进程通信demo,亲测可用,binder机制,改完bug,好用.
项目包括两部分,客户端和服务端,分别介绍了两个客户端的通信实现,及潜在的问题,由浅入深,其中包括基本数据类型和自定义数据类型的接口格式。