首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网络技术 > 网络基础 >

AIDL引见

2012-07-08 
AIDL介绍感谢分享,原创地址:http://blog.csdn.net/saintswordsman/archive/2010/01/04/5130947.aspx欢迎阅

AIDL介绍
感谢分享,原创地址:
http://blog.csdn.net/saintswordsman/archive/2010/01/04/5130947.aspx
欢迎阅读本文,你能关注本文,你知道你需要进程间通信、需要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
view plaincopy to clipboardprint?
1.package com.styleflying.AIDL;
2.interface ITaskCallback {
3.void performAction();
文件:forService.aidl
view plaincopy to clipboardprint?
1.package com.styleflying.AIDL;
2.import com.styleflying.AIDL.forActivity;
3.interface ITaskBinder {
4.void registerTestCall(ITaskCallback tc);
5.void invokCallBack();
6.}
这两个文件和Java文件放置的地方一样,看包名。
在Eclipse中它们将被自动编译为forActivity.java和forService.java,它们存放在gen目录下。为了方便手头无法演练的读者,代码贴上,不用细看。
文件forActivity.java:
view plaincopy to clipboardprint?
1./*
2.* This file is auto-generated.  DO NOT MODIFY.
3.* Original file: D:\\workspace\\AIDLTest\\src\\com\\styleflying\\AIDL\\forActivity.aidl
4.*/
5.package com.styleflying.AIDL;
6.import java.lang.String;
7.import android.os.RemoteException;
8.import android.os.IBinder;
9.import android.os.IInterface;
10.import android.os.Binder;
11.import android.os.Parcel;
12.public interface forActivity extends android.os.IInterface
13.{
14./** Local-side IPC implementation stub class. */
15.public static abstract class Stub extends android.os.Binder implements com.styleflying.AIDL.forActivity
16.{
17.private static final java.lang.String DESCRIPTOR = ”com.styleflying.AIDL.forActivity”;
18./** Construct the stub at attach it to the interface. */
19.public Stub()
20.{
21.this.attachInterface(this, DESCRIPTOR);
22.}
23./**
24.* Cast an IBinder object into an forActivity interface,
25.* generating a proxy if needed.
26.*/
27.public static com.styleflying.AIDL.forActivity asInterface(android.os.IBinder obj)
28.{
29.if ((obj==null)) {
30.return null;
31.}
32.android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
33.if (((iin!=null)&&(iin instanceof com.styleflying.AIDL.forActivity))) {
34.return ((com.styleflying.AIDL.forActivity)iin);
35.}
36.return new com.styleflying.AIDL.forActivity.Stub.Proxy(obj);
37.}
38.public android.os.IBinder asBinder()
39.{
40.return this;
41.}
42.@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
43.{
44.switch (code)
45.{
46.case INTERFACE_TRANSACTION:
47.{
48.reply.writeString(DESCRIPTOR);
49.return true;
50.}
51.case TRANSACTION_performAction:
52.{
53.data.enforceInterface(DESCRIPTOR);
54.this.performAction();
55.reply.writeNoException();
56.return true;
57.}
58.}
59.return super.onTransact(code, data, reply, flags);
60.}
61.private static class Proxy implements com.styleflying.AIDL.forActivity
62.{
63.private android.os.IBinder mRemote;
64.Proxy(android.os.IBinder remote)
65.{
66.mRemote = remote;
67.}
68.public android.os.IBinder asBinder()
69.{
70.return mRemote;
71.}
72.public java.lang.String getInterfaceDescriptor()
73.{
74.return DESCRIPTOR;
75.}
76.public void performAction() throws android.os.RemoteException
77.{
78.android.os.Parcel _data = android.os.Parcel.obtain();
79.android.os.Parcel _reply = android.os.Parcel.obtain();
80.try {
81._data.writeInterfaceToken(DESCRIPTOR);
82.mRemote.transact(Stub.TRANSACTION_performAction, _data, _reply, 0);
83._reply.readException();
84.}
85.finally {
86._reply.recycle();
87._data.recycle();
88.}
89.}
90.}
91.static final int TRANSACTION_performAction = (IBinder.FIRST_CALL_TRANSACTION + 0);
92.}
93.public void performAction() throws android.os.RemoteException;
94.}
文件forService.java:
+ expand sourceview plaincopy to clipboardprint?
?????????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:
view plaincopy to clipboardprint?
1.package com.styleflying.AIDL;
2.import android.app.Activity;
3.import android.content.ComponentName;
4.import android.content.Context;
5.import android.content.Intent;
6.import android.content.ServiceConnection;
7.import android.os.Bundle;
8.import android.os.IBinder;
9.import android.os.RemoteException;
10.import android.util.Log;
11.import android.view.View;
12.import android.view.View.OnClickListener;
13.import android.widget.Button;
14.import android.widget.Toast;
15.public class mAIDLActivity extends Activity {
16.private static final String TAG = ”AIDLActivity”;
17.private Button btnOk;
18.private Button btnCancel;
19.private Button btnCallBack;
20.private void Log(String str) {
21.Log.d(TAG, ”—— ” + str + ”——”);
22.}
23.private forActivity mCallback = new forActivity.Stub() {
24.public void performAction() throws RemoteException
25.{
26.Toast.makeText(mAIDLActivity.this, ”this toast is called from service”, 1).show();
27.}
28.};
29.forService mService;
30.private ServiceConnection mConnection = new ServiceConnection() {
31.public void onServiceConnected(ComponentName className,
32.IBinder service) {
33.mService = forService.Stub.asInterface(service);
34.try {
35.mService.registerTestCall(mCallback);}
36.catch (RemoteException e) {
37.}
38.}
39.public void onServiceDisconnected(ComponentName className) {
40.Log(“disconnect service”);
41.mService = null;
42.}
43.};
44.@Override
45.public void onCreate(Bundle icicle) {
46.super.onCreate(icicle);
47.setContentView(R.layout.main);
48.btnOk = (Button)findViewById(R.id.btn_ok);
49.btnCancel = (Button)findViewById(R.id.btn_cancel);
50.btnCallBack = (Button)findViewById(R.id.btn_callback);
51.btnOk.setOnClickListener(new OnClickListener() {
52.public void onClick(View v) {
53.Bundle args = new Bundle();
54.Intent intent = new Intent(mAIDLActivity.this, mAIDLService.class);
55.intent.putExtras(args);
56.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
57.startService(intent);
58.}
59.});
60.btnCancel.setOnClickListener(new OnClickListener() {
61.public void onClick(View v) {
62.unbindService(mConnection);
63.//stopService(intent);
64.}
65.});
66.btnCallBack.setOnClickListener(new OnClickListener() {
67.@Override
68.public void onClick(View v)
69.{
70.try
71.{
72.mService.invokCallBack();
73.} catch (RemoteException e)
74.{
75.// TODO Auto-generated catch block
76.e.printStackTrace();
77.}
78.}
79.});
80.}
81.}
很短,相信大家很容易看明白。注意mConnection,它的onServiceConnected()中有一句mService = forService.Stub.asInterface(service);给mService赋值了,这个mService是一个forService,而service是onServiceConnected()传进来的参数,onServiceConnected()会在连接Service的时候被系统调用,这个service参数的值来自哪里呢?看mAIDLService.java:
view plaincopy to clipboardprint?
1.package com.styleflying.AIDL;
2.import android.app.Service;
3.import android.content.Intent;
4.import android.os.IBinder;
5.import android.os.RemoteCallbackList;
6.import android.os.RemoteException;
7.import android.util.Log;
8.public class mAIDLService extends Service {
9.private static final String TAG = ”AIDLService”;
10.private forActivity callback;
11.private void Log(String str) {
12.Log.d(TAG, ”—— ” + str + ”——”);
13.}
14.@Override
15.public void onCreate() {
16.Log(“service create”);
17.}
18.@Override
19.public void onStart(Intent intent, int startId) {
20.Log(“service start id=” + startId);
21.}
22.@Override
23.public IBinder onBind(Intent t) {
24.Log(“service on bind”);
25.return mBinder;
26.}
27.@Override
28.public void onDestroy() {
29.Log(“service on destroy”);
30.super.onDestroy();
31.}
32.@Override
33.public boolean onUnbind(Intent intent) {
34.Log(“service on unbind”);
35.return super.onUnbind(intent);
36.}
37.public void onRebind(Intent intent) {
38.Log(“service on rebind”);
39.super.onRebind(intent);
40.}
41.private final forService.Stub mBinder = new forService.Stub() {
42.@Override
43.public void invokCallBack() throws RemoteException
44.{
45.callback.performAction();
46.}
47.@Override
48.public void registerTestCall(forActivity cb) throws RemoteException
49.{
50.callback = cb;
51.}
52.};
53.}
注意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)。

热点排行
Bad Request.