看了几篇,这篇文章算算看懂了记录一下,另外附上我看完这篇文章后写的测试代码。(不能上传附件,如果需要发邮件索取可以,shuicg.php@gmail.com)
转自:http://blog.csdn.net/saintswordsman/article/details/5130947
欢迎阅读本文,你能关注本文,你知道你需要进程间通信、需要AIDL(以及Binder),那么可以默认你对这些概念已经有了一些了解,你(大致)知道它们是什么,它们有什么用,所以为了节约大家的眼力和时间,在此我不复制粘贴网上泛滥的博客或者翻译冗长的android文档。
关于AIDL的介绍在文档:docs/guide/developing/tools/aidl.html
关于IBinder的介绍在文档:docs/reference/android/os/IBinder.html
以及Binder:docs/reference/android/os/Binder.html
在后文中,我将以我自己的理解向你介绍相关的概念。以我目前粗浅的经验,应用程序使用AIDL的地方,几乎都和Service有关,所以你也需要知道一些关于Service的知识。日后得闲我也会继续写一些关于Service的贴。
本文将以一个例子来和你分享使用AIDL的基础技能,这个例子里有:
1、一个类mAIDLActivity,继承Activity。里面有三个按钮,text分别为StartService,StopService,CallbackTest。
2、一个类mAIDLService,继承Service。为了充分展示ADIL的功能,它做以下工作:当用户点击CallbackTest按钮时,从mAIDLActivity调用mAIDLService中的Stub对象的一个方法invokCallBack(),而这个方法又会调用mAIDLActivity中Stub对象的一个方法performAction(),这个方法在屏幕上显示一个toast。没什么意义,只是展示一下AIDL如何使用。
3、两个AIDL文件:forService.aidl和forActivity.aidl。对应名字,在Service和Activity中分别有对象需要用到它们定义的接口。
4、相关XML文件,略过。关于manifest中Service的语法,见docs/guide/topics/manifest/service-element.html。你也可以简单地在<application></application>中加入
<service android:name=".mAIDLService" android:process=":remote"> </service>
开发环境为Eclipse。
拣重要的先说,来看看aidl文件的内容:
文件:forActivity.aidl
-
packagecom.styleflying.AIDL;
-
interfaceforActivity{
-
voidperformAction();
-
}
文件:forService.aidl
-
packagecom.styleflying.AIDL;
-
importcom.styleflying.AIDL.forActivity;
-
interfaceforService{
-
voidregisterTestCall(forActivitycb);
-
voidinvokCallBack();
-
}
这两个文件和Java文件放置的地方一样,看包名。
在Eclipse中它们将被自动编译为forActivity.java和forService.java,它们存放在gen目录下。为了方便手头无法演练的读者,代码贴上,不用细看。
文件forActivity.java:
-
-
-
-
-
packagecom.styleflying.AIDL;
-
importjava.lang.String;
-
importandroid.os.RemoteException;
-
importandroid.os.IBinder;
-
importandroid.os.IInterface;
-
importandroid.os.Binder;
-
importandroid.os.Parcel;
-
publicinterfaceforActivityextendsandroid.os.IInterface
-
{
-
-
publicstaticabstractclassStubextendsandroid.os.Binderimplementscom.styleflying.AIDL.forActivity
-
{
-
privatestaticfinaljava.lang.StringDESCRIPTOR="com.styleflying.AIDL.forActivity";
-
-
publicStub()
-
{
-
this.attachInterface(this,DESCRIPTOR);
-
}
-
-
-
-
-
publicstaticcom.styleflying.AIDL.forActivityasInterface(android.os.IBinderobj)
-
{
-
if((obj==null)){
-
returnnull;
-
}
-
android.os.IInterfaceiin=(android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
-
if(((iin!=null)&&(iininstanceofcom.styleflying.AIDL.forActivity))){
-
return((com.styleflying.AIDL.forActivity)iin);
-
}
-
returnnewcom.styleflying.AIDL.forActivity.Stub.Proxy(obj);
-
}
-
publicandroid.os.IBinderasBinder()
-
{
-
returnthis;
-
}
-
@OverridepublicbooleanonTransact(intcode,android.os.Parceldata,android.os.Parcelreply,intflags)throwsandroid.os.RemoteException
-
{
-
switch(code)
-
{
-
caseINTERFACE_TRANSACTION:
-
{
-
reply.writeString(DESCRIPTOR);
-
returntrue;
-
}
-
caseTRANSACTION_performAction:
-
{
-
data.enforceInterface(DESCRIPTOR);
-
this.performAction();
-
reply.writeNoException();
-
returntrue;
-
}
-
}
-
returnsuper.onTransact(code,data,reply,flags);
-
}
-
privatestaticclassProxyimplementscom.styleflying.AIDL.forActivity
-
{
-
privateandroid.os.IBindermRemote;
-
Proxy(android.os.IBinderremote)
-
{
-
mRemote=remote;
-
}
-
publicandroid.os.IBinderasBinder()
-
{
-
returnmRemote;
-
}
-
publicjava.lang.StringgetInterfaceDescriptor()
-
{
-
returnDESCRIPTOR;
-
}
-
publicvoidperformAction()throwsandroid.os.RemoteException
-
{
-
android.os.Parcel_data=android.os.Parcel.obtain();
-
android.os.Parcel_reply=android.os.Parcel.obtain();
-
try{
-
_data.writeInterfaceToken(DESCRIPTOR);
-
mRemote.transact(Stub.TRANSACTION_performAction,_data,_reply,0);
-
_reply.readException();
-
}
-
finally{
-
_reply.recycle();
-
_data.recycle();
-
}
-
}
-
}
-
staticfinalintTRANSACTION_performAction=(IBinder.FIRST_CALL_TRANSACTION+0);
-
}
-
publicvoidperformAction()throwsandroid.os.RemoteException;
-
}
文件forService.java:
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
两段代码差不多,前面基本一样,从后面看,最后跟着我们在AIDL中自定义的方法,没有实现。两个文件各定义一个了接口,这两个接口分别会在Activity和Service中使用,在那里我们将实现自定义的方法。两个接口中都定义了一个抽象类Stub,实现所在的接口。Stub中又有一个类Proxy。Stub中有一个static的asInterface()方法,里面有很多return语句,在mAIDLActivity中调用它时,它返回一个新创建的内部类Proxy对象。
这个Stub对我们来说很有用,它继承了Binder。Binder有什么用呢?一个类,继承了Binder,那么它的对象就可以被远程的进程使用了(前提是远程进程获取了这个类的对象【对象的引用】,至于如如何获得看下文),在本例中就是说,如果一个Service中有一个继承了Stub的类的对象,那么这个对象中的方法就可以在Activity中使用,对Activity也是这样。至于Binder的细节,网上有很多贴介绍,看不明白也不影响我们完成这个例子。
再看mAIDLActivity.java:
-
packagecom.styleflying.AIDL;
-
importandroid.app.Activity;
-
importandroid.content.ComponentName;
-
importandroid.content.Context;
-
importandroid.content.Intent;
-
importandroid.content.ServiceConnection;
-
importandroid.os.Bundle;
-
importandroid.os.IBinder;
-
importandroid.os.RemoteException;
-
importandroid.util.Log;
-
importandroid.view.View;
-
importandroid.view.View.OnClickListener;
-
importandroid.widget.Button;
-
importandroid.widget.Toast;
-
publicclassmAIDLActivityextendsActivity{
-
privatestaticfinalStringTAG="AIDLActivity";
-
privateButtonbtnOk;
-
privateButtonbtnCancel;
-
privateButtonbtnCallBack;
-
-
privatevoidLog(Stringstr){
-
Log.d(TAG,"------"+str+"------");
-
}
-
-
privateforActivitymCallback=newforActivity.Stub(){
-
publicvoidperformAction()throwsRemoteException
-
{
-
Toast.makeText(mAIDLActivity.this,"thistoastiscalledfromservice",1).show();
-
}
-
};
-
-
forServicemService;
-
privateServiceConnectionmConnection=newServiceConnection(){
-
publicvoidonServiceConnected(ComponentNameclassName,
-
IBinderservice){
-
mService=forService.Stub.asInterface(service);
-
try{
-
mService.registerTestCall(mCallback);}
-
catch(RemoteExceptione){
-
-
}
-
}
-
publicvoidonServiceDisconnected(ComponentNameclassName){
-
Log("disconnectservice");
-
mService=null;
-
}
-
};
-
@Override
-
publicvoidonCreate(Bundleicicle){
-
super.onCreate(icicle);
-
setContentView(R.layout.main);
-
btnOk=(Button)findViewById(R.id.btn_ok);
-
btnCancel=(Button)findViewById(R.id.btn_cancel);
-
btnCallBack=(Button)findViewById(R.id.btn_callback);
-
btnOk.setOnClickListener(newOnClickListener(){
-
publicvoidonClick(Viewv){
-
Bundleargs=newBundle();
-
Intentintent=newIntent(mAIDLActivity.this,mAIDLService.class);
-
intent.putExtras(args);
-
bindService(intent,mConnection,Context.BIND_AUTO_CREATE);
-
startService(intent);
-
}
-
});
-
btnCancel.setOnClickListener(newOnClickListener(){
-
publicvoidonClick(Viewv){
-
unbindService(mConnection);
-
-
}
-
});
-
btnCallBack.setOnClickListener(newOnClickListener(){
-
-
@Override
-
publicvoidonClick(Viewv)
-
{
-
try
-
{
-
mService.invokCallBack();
-
}catch(RemoteExceptione)
-
{
-
-
e.printStackTrace();
-
}
-
}
-
});
-
}
-
}
很短,相信大家很容易看明白。注意mConnection,它的onServiceConnected()中有一句mService = forService.Stub.asInterface(service);给mService赋值了,这个mService是一个forService,而service是onServiceConnected()传进来的参数,onServiceConnected()会在连接Service的时候被系统调用,这个service参数的值来自哪里呢?看mAIDLService.java:
-
packagecom.styleflying.AIDL;
-
importandroid.app.Service;
-
importandroid.content.Intent;
-
importandroid.os.IBinder;
-
importandroid.os.RemoteCallbackList;
-
importandroid.os.RemoteException;
-
importandroid.util.Log;
-
publicclassmAIDLServiceextendsService{
-
privatestaticfinalStringTAG="AIDLService";
-
privateforActivitycallback;
-
privatevoidLog(Stringstr){
-
Log.d(TAG,"------"+str+"------");
-
}
-
@Override
-
publicvoidonCreate(){
-
Log("servicecreate");
-
}
-
@Override
-
publicvoidonStart(Intentintent,intstartId){
-
Log("servicestartid="+startId);
-
}
-
-
@Override
-
publicIBinderonBind(Intentt){
-
Log("serviceonbind");
-
returnmBinder;
-
}
-
@Override
-
publicvoidonDestroy(){
-
Log("serviceondestroy");
-
super.onDestroy();
-
}
-
@Override
-
publicbooleanonUnbind(Intentintent){
-
Log("serviceonunbind");
-
returnsuper.onUnbind(intent);
-
}
-
publicvoidonRebind(Intentintent){
-
Log("serviceonrebind");
-
super.onRebind(intent);
-
}
-
privatefinalforService.StubmBinder=newforService.Stub(){
-
@Override
-
publicvoidinvokCallBack()throwsRemoteException
-
{
-
callback.performAction();
-
-
}
-
@Override
-
publicvoidregisterTestCall(forActivitycb)throwsRemoteException
-
{
-
callback=cb;
-
-
}
-
-
};
-
}
注意onBind(),它的返回类型为IBinder,返回了一个mBinder,看看mBinder的定义:
private final forService.Stub mBinder = new forService.Stub() {
@Override
public void invokCallBack() throws RemoteException
{
callback.performAction();
}
@Override
public void registerTestCall(forActivity cb) throws RemoteException
{
callback = cb;
}
};
它是实现了我们在AIDL中定义的方法,这个mBinder最终返回给了mAIDLActivity中的mService,于是在mAIDLActivity中可以使用mBinder中的方法了。在mAIDLActivity中也有一个类似mBinder的对象,看看定义:
private forActivity mCallback = new forActivity.Stub()
{
public void performAction() throws RemoteException
{
Toast.makeText(mAIDLActivity.this, "this toast is called from service", 1).show();
}
};
我们要在界面上显示一个toast,就是在这里实现的。这个对象,在mConnection的onServiceConnected()被调用时,通过调用mService(也就是远程的mAIDLService中的mBinder)的registerTestCall(),传递给了mAIDLService,于是在mAIDLService中可以调用performAction()了。
很啰嗦,只为了能把这个细节说清楚。请大家认真看,我尽量避免错别字、混乱的大小写和逻辑不清的语法,相信你会看明白。是不是很简单?再啰嗦一下,做一个大致总结,我们使用AIDL是要做什么呢:
让Acticity(或者说一个进程/一个类?)和Service(或者说远端进程/远端类/对象?)获取对方的一个Stub对象,这个对象在定义时实现了我们在AIDL中定义的方法,于是这些远程对象中的方法可以在本地使用了。如果这种使用(通信)是单向的,比如只是Activity需要通知Service做什么,那么只要Service中有一个Stub对象,并且传给Acticity就够了。
至于如何获得远程的Stub,参看上面的代码,看mConnection、registerTestCall、onRebind,它们展示了一种方法。
另外,有时候我们可能在一个类中有多个Stub对象,它们都要给远程交互的类的实例,这个时候可以考虑使用RemoteCallbackList<>(docs/reference/android/os/RemoteCallbackList.html)。
欢迎阅读、收藏本文。例子随手写的,功能只在演示AIDL的使用。您可以转载本文,但请勿盲目乱贴。不是我小气,我不权威,我怕它被贴到泛滥,以讹传讹,害了人。
分享到:
相关推荐
Android 进程间通信AIDL demo 博客地址:http://blog.csdn.net/bigboysunshine/article/details/70228223
android进程间通信之AIDL的简单的示例代码
Android进程间通信AIDL技术讲解
本文主要是对进程间通信方式(AIDL)进行验证而编写的简单demo,demo主要包含服务器端与客户端,在使用过程中C端与S端aidl文件的包名必须保持一致且C端与S端需要安装在同一设备上方可进行通讯
Android进程间的通信之AIDL简单实例,主要是一下流程,希望大神们勿喷,也希望对初学者有所帮助
Android使用AIDL实现进程间通信
andorid 不同进程间的通信, uses the aidl to comple the demo,hope you can learn ,and give me you idear .
IPCCommunication是通过两种方式实现进程间通信,一种是手写binder实现进程间通信,互相传递使用Bunder,可以在Bunder中自定义协议,另外一种是基于Message,客户端与服务端之间使用Message进行通信;
AIDL----Android进程间通信(IPC)浅析测试代码,注释非常详细
android根据不同任务创建不同进程,并通过AIDL进行进程间通信
进程间通信涉及到客户端和服务端, 肯定有绑定服务的过程, 所以要阅读一下Android Service相关的知识, 跨进程通信的媒介aidl文件,我们也必须要了解怎么创建的,有什么规则,所以请先阅读一下Android AIDL使用这篇...
android使用aidl实现进程间通信,而且是双向通信
Android aidl 实现进程间通信(IPC)
NULL 博文链接:https://android-zhang.iteye.com/blog/1850180
使用AIDL完成进程间的简单通信
一个例子工程,主要介绍AIDL的使用和原理浅析
demo采用计算器的例子实现了AIDL进程间通讯的工作机制,包含服务端的数据处理和客户端的数据采集并展示。详情可查看个人博客《Android开发之进程间通信AIDL的探究和学习》。
【一图流】_02_一张图看懂 Android 进程间通信(IPC)Binder机制: 此图表述了Android系统_进程间通信(IPC)机制全部体系,其中重点放在 Android系统中 重用 的 Binder机制 上,详尽细致,希望对大家有用;
Android进程间通信 AIDL Service 一、服务端结构 服务端需要处理的有: 1.处理对象,对象内方法,注意:AIDL 只能对函数起作用; 2.处理服务; 3.配置文件; 二、客户端 配置 1.对象,切记,与服务端的对象完全一致...