欢迎阅读本文,你能关注本文,你知道你需要进程间通信、需要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
-
package
com.styleflying.AIDL;
-
interface
forActivity {
-
void
performAction();
-
}
文件:forService.aidl
-
package
com.styleflying.AIDL;
-
import
com.styleflying.AIDL.forActivity;
-
interface
forService {
-
void
registerTestCall(forActivity cb);
-
void
invokCallBack();
-
}
这两个文件和Java文件放置的地方一样,看包名。
在Eclipse中它们将被自动编译为forActivity.java和forService.java,它们存放在gen目录下。为了方便手头无法演练的读者,代码贴上,不用细看。
文件forActivity.java:
-
-
-
-
-
package
com.styleflying.AIDL;
-
import
java.lang.String;
-
import
android.os.RemoteException;
-
import
android.os.IBinder;
-
import
android.os.IInterface;
-
import
android.os.Binder;
-
import
android.os.Parcel;
-
public
interface
forActivity
extends
android.os.IInterface
-
{
-
-
public
static
abstract
class
Stub
extends
android.os.Binder
implements
com.styleflying.AIDL.forActivity
-
{
-
private
static
final
java.lang.String DESCRIPTOR =
"com.styleflying.AIDL.forActivity"
;
-
-
public
Stub()
-
{
-
this
.attachInterface(
this
, DESCRIPTOR);
-
}
-
-
-
-
-
public
static
com.styleflying.AIDL.forActivity asInterface(android.os.IBinder obj)
-
{
-
if
((obj==
null
)) {
-
return
null
;
-
}
-
android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
-
if
(((iin!=
null
)&&(iin
instanceof
com.styleflying.AIDL.forActivity))) {
-
return
((com.styleflying.AIDL.forActivity)iin);
-
}
-
return
new
com.styleflying.AIDL.forActivity.Stub.Proxy(obj);
-
}
-
public
android.os.IBinder asBinder()
-
{
-
return
this
;
-
}
-
@Override
public
boolean
onTransact(
int
code, android.os.Parcel data, android.os.Parcel reply,
int
flags)
throws
android.os.RemoteException
-
{
-
switch
(code)
-
{
-
case
INTERFACE_TRANSACTION:
-
{
-
reply.writeString(DESCRIPTOR);
-
return
true
;
-
}
-
case
TRANSACTION_performAction:
-
{
-
data.enforceInterface(DESCRIPTOR);
-
this
.performAction();
-
reply.writeNoException();
-
return
true
;
-
}
-
}
-
return
super
.onTransact(code, data, reply, flags);
-
}
-
private
static
class
Proxy
implements
com.styleflying.AIDL.forActivity
-
{
-
private
android.os.IBinder mRemote;
-
Proxy(android.os.IBinder remote)
-
{
-
mRemote = remote;
-
}
-
public
android.os.IBinder asBinder()
-
{
-
return
mRemote;
-
}
-
public
java.lang.String getInterfaceDescriptor()
-
{
-
return
DESCRIPTOR;
-
}
-
public
void
performAction()
throws
android.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();
-
}
-
}
-
}
-
static
final
int
TRANSACTION_performAction = (IBinder.FIRST_CALL_TRANSACTION +
0
);
-
}
-
public
void
performAction()
throws
android.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:
-
package
com.styleflying.AIDL;
-
import
android.app.Activity;
-
import
android.content.ComponentName;
-
import
android.content.Context;
-
import
android.content.Intent;
-
import
android.content.ServiceConnection;
-
import
android.os.Bundle;
-
import
android.os.IBinder;
-
import
android.os.RemoteException;
-
import
android.util.Log;
-
import
android.view.View;
-
import
android.view.View.OnClickListener;
-
import
android.widget.Button;
-
import
android.widget.Toast;
-
public
class
mAIDLActivity
extends
Activity {
-
private
static
final
String TAG =
"AIDLActivity"
;
-
private
Button btnOk;
-
private
Button btnCancel;
-
private
Button btnCallBack;
-
-
private
void
Log(String str) {
-
Log.d(TAG, "------ "
+ str +
"------"
);
-
}
-
-
private
forActivity mCallback =
new
forActivity.Stub() {
-
public
void
performAction()
throws
RemoteException
-
{
-
Toast.makeText(mAIDLActivity.this
,
"this toast is called from service"
,
1
).show();
-
}
-
};
-
-
forService mService;
-
private
ServiceConnection mConnection =
new
ServiceConnection() {
-
public
void
onServiceConnected(ComponentName className,
-
IBinder service) {
-
mService = forService.Stub.asInterface(service);
-
try
{
-
mService.registerTestCall(mCallback);}
-
catch
(RemoteException e) {
-
-
}
-
}
-
public
void
onServiceDisconnected(ComponentName className) {
-
Log("disconnect service"
);
-
mService = null
;
-
}
-
};
-
@Override
-
public
void
onCreate(Bundle icicle) {
-
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(new
OnClickListener() {
-
public
void
onClick(View v) {
-
Bundle args = new
Bundle();
-
Intent intent = new
Intent(mAIDLActivity.
this
, mAIDLService.
class
);
-
intent.putExtras(args);
-
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
-
startService(intent);
-
}
-
});
-
btnCancel.setOnClickListener(new
OnClickListener() {
-
public
void
onClick(View v) {
-
unbindService(mConnection);
-
-
}
-
});
-
btnCallBack.setOnClickListener(new
OnClickListener() {
-
-
@Override
-
public
void
onClick(View v)
-
{
-
try
-
{
-
mService.invokCallBack();
-
} catch
(RemoteException e)
-
{
-
-
e.printStackTrace();
-
}
-
}
-
});
-
}
-
}
很短,相信大家很容易看明白。注意mConnection,它的onServiceConnected()中有一句mService = forService.Stub.asInterface(service);给mService赋值了,这个mService是一个forService,而service是onServiceConnected()传进来的参数,onServiceConnected()会在连接Service的时候被系统调用,这个service参数的值来自哪里呢?看mAIDLService.java:
-
package
com.styleflying.AIDL;
-
import
android.app.Service;
-
import
android.content.Intent;
-
import
android.os.IBinder;
-
import
android.os.RemoteCallbackList;
-
import
android.os.RemoteException;
-
import
android.util.Log;
-
public
class
mAIDLService
extends
Service {
-
private
static
final
String TAG =
"AIDLService"
;
-
private
forActivity callback;
-
private
void
Log(String str) {
-
Log.d(TAG, "------ "
+ str +
"------"
);
-
}
-
@Override
-
public
void
onCreate() {
-
Log("service create"
);
-
}
-
@Override
-
public
void
onStart(Intent intent,
int
startId) {
-
Log("service start id="
+ startId);
-
}
-
-
@Override
-
public
IBinder onBind(Intent t) {
-
Log("service on bind"
);
-
return
mBinder;
-
}
-
@Override
-
public
void
onDestroy() {
-
Log("service on destroy"
);
-
super
.onDestroy();
-
}
-
@Override
-
public
boolean
onUnbind(Intent intent) {
-
Log("service on unbind"
);
-
return
super
.onUnbind(intent);
-
}
-
public
void
onRebind(Intent intent) {
-
Log("service on rebind"
);
-
super
.onRebind(intent);
-
}
-
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;
-
-
}
-
-
};
-
}
注意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的使用。您可以转载本文,但请勿盲目乱贴。不是我小气,我不权威,我怕它被贴到泛滥,以讹传讹,害了人。
相关推荐
在这个"aidl-sample.zip"压缩包中,我们预计将找到一个完整的示例,包括服务端(Server)和客户端(Client)的代码,帮助开发者理解如何在实际项目中运用AIDL。** ### AIDL基础 1. **接口定义**: 在AIDL中,开发者...
本示例“android-AIDL-服务端+客户端Demo”展示了如何通过AIDL来创建一个服务端并由客户端进行调用,同时也包含了辅助工具类,如hex工具类用于十六进制转换,以及安卓证书MD5和SHA-1获取工具类,这些工具类用于安全...
AIDL(Android Interface Definition Language)是Android平台提供的一种强大的工具,专门用于实现进程间的通信。AIDL使得开发者可以定义接口,允许一个应用程序组件在另一个组件中调用方法,即使这两个组件处于不同...
本教程将深入解析"AIDL-demo"源码,以帮助你理解AIDL的工作原理和实际应用。 **1. AIDL基础知识** AIDL文件是一个文本文件,使用特定的语法来声明方法签名,类似于Java接口。通过AIDL,Android系统会自动生成对应的...
**Android进程间通信(IPC):AIDL详解** 在Android系统中,进程间通信(IPC,Inter-Process Communication)是应用程序之间数据交换的关键技术。AIDL(Android Interface Definition Language)是Android提供的一...
AIDL,全称为Android Interface Definition Language,是Android系统中用于实现进程间通信(IPC, Inter-Process Communication)的一种工具。由于Android系统中的每个应用程序都运行在独立的进程空间,因此当需要在...
在Android系统中,AIDL(Android Interface Definition Language)是一种用于实现跨进程通信(IPC, Inter-Process Communication)的重要工具。AIDL使得一个应用程序能够暴露其服务给其他应用程序,即使它们运行在...
在Android开发中,AIDL(Android Interface Definition Language)是一种用于实现进程间通信(IPC, Inter-Process Communication)的工具,允许不同进程之间的组件相互调用方法。本压缩包"安卓AIDL相关-AIDLService...
【Android-AIDL(原文档翻译)】 Android接口描述语言(AIDL)是Android系统提供的一种接口定义工具,用于处理进程间通信(IPC)。通常,Android应用程序在各自独立的进程中运行,但当需要不同进程间传递对象时,就...
本教程以“aidl-android-studio1.3.1”为例,介绍了如何在Android Studio 1.3.1版本下使用AIDL实现Activity与Service之间的进程间通信。 首先,理解AIDL的基本概念是至关重要的。AIDL定义了一种接口,这个接口就是...
而AIDL(Android Interface Definition Language)是Android系统提供的一种接口定义语言,用于处理进程间通信(IPC, Inter-Process Communication)。当需要在第三方应用中与WPS Office进行交互时,AIDL就成为了一个...
AIDL(Android Interface Definition Language)是Binder架构的一部分,用于定义跨进程通信的接口,使得不同进程间的对象可以相互通信,就像在同一进程中调用方法一样。本文将深入探讨AIDL的使用及其在Binder架构中...
在Android开发中,Android Interface Definition Language(AIDL)是一种强大的工具,用于实现进程间通信(IPC, Inter-Process Communication)。AIDL使得不同的Android组件,如服务(Service)和活动(Activity),...
aidl-Demo 遇到的问题: 1. Override的onServiceConnected无法回调:AndroidManifest的service的包名称要正确。 2.注意客户服务两端包名要一样。
为了解决跨进程通信(IPC,Inter-Process Communication)的问题,Android引入了Binder机制,并在此基础上发展出了Android Interface Definition Language(AIDL)。AIDL允许开发者定义接口,使得一个应用可以暴露...
在这个"AIDL-Demo服务端,客户端二合一"项目中,开发者提供了一个全面的示例,展示了如何在Android应用中使用AIDL。通过这个Demo,我们可以深入理解AIDL的工作原理以及如何在实际开发中运用。 首先,我们需要了解...
Android AIDL基础-利用AIDL实现客户端向服务端传递Listener接口
本资料包“Android IPC通信 - AIDL.zip”主要关注Android中的AIDL(Android Interface Definition Language)技术,它是实现服务(Service)跨进程通信的一种高效方法。下面将详细介绍AIDL及其在Android Service中的...
AIDL概述:AIDL是一个缩写,全称是Android Interface Definition Language,也就是Android接口定义语言,设计这门语言的目的是为了实现进程间通信。接下来我写了两个demo(AildeService和AidleClient),他们之间...