Android Service总结06 之AIDL
版本 |
版本说明 |
发布时间 |
发布人 |
V1.0 |
初始版本 |
2013-04-03 |
Skywang |
1 AIDL介绍
AIDL,即Android InterfaceDefinition Language。
Android使用AIDL来完成进程间通信(IPC),并且一般在服务需要接受不同应用多线程的请求时才需要使用AIDL;如果是同一个应用内的请求使用Binder实现即可;如果只是应用间通信而不是多线程处理的话使用Messenger,当然这两种情况也可以使用AIDL。本地进程和远程进程使用AIDL有所不同,本地进程内调用时会都在调用的线程内执行,远程进程使用是通过Service进程内一个由系统维护的线程池发出调用,所以可能是未知线程同时调用,需要注意线程安全问题。
2 AIDL示例
创建AIDL服务的步骤: (01)创建.aidl文件。 .aidl是接口文件,它定义了服务所能提供的功能。 (02)实现.aidl所定义的接口。 (03)将接口开放给其它应用程序。
2.1 创建.aidl文件
(01)打开eclipse,新建工程”AIDLServiceImpl”,然后在工程的“com.text”包下创建“MyAIDLInterface.aidl”文件。
如下图:
(02)编辑“MyAIDLInterface.aidl”,提供doubleValue(int val)和halfValue(int value)服务。
“MyAIDLInterface.aidl”代码如下:
package com.test; interface MyAIDLInterface { void doubleValue(int val); void halfValue(int val); }
(03)编译工程,在“gen”目录下会自动生成与“MyAIDLInterface.aidl”对应的“MyAIDLInterface.java”文件。
如下图:
“MyAIDLInterface.java”代码如下:
/* * This file is auto-generated. DO NOT MODIFY. * Original file: F:\\workout\\android\\AIDLServiceImpl\\src\\com\\test\\MyAIDLInterface.aidl */ package com.test; public interface MyAIDLInterface extends android.os.IInterface { /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.test.MyAIDLInterface { private static final java.lang.String DESCRIPTOR = "com.test.MyAIDLInterface"; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.test.MyAIDLInterface interface, * generating a proxy if needed. */ public static com.test.MyAIDLInterface 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.test.MyAIDLInterface))) { return ((com.test.MyAIDLInterface)iin); } return new com.test.MyAIDLInterface.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_doubleValue: { data.enforceInterface(DESCRIPTOR); int _arg0; _arg0 = data.readInt(); this.doubleValue(_arg0); reply.writeNoException(); return true; } case TRANSACTION_halfValue: { data.enforceInterface(DESCRIPTOR); int _arg0; _arg0 = data.readInt(); this.halfValue(_arg0); reply.writeNoException(); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.test.MyAIDLInterface { 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 doubleValue(int val) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(val); mRemote.transact(Stub.TRANSACTION_doubleValue, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } public void halfValue(int val) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(val); mRemote.transact(Stub.TRANSACTION_halfValue, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } } static final int TRANSACTION_doubleValue = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_halfValue = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); } public void doubleValue(int val) throws android.os.RemoteException; public void halfValue(int val) throws android.os.RemoteException; }
2.2 实现.aidl所定义的接口
(04)在“com.test”包下新建文件MyAIDLService.java,并实现doubleValue(int val)和halfValue(int value)接口。
如下图:
MyAIDLService.java的代码如下:
package com.test; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; public class MyAIDLService extends Service{ private static final String TAG = "skywang-->MyAIDLService"; private MyAIDLInterface.Stub myBinder = new MyAIDLInterface.Stub() { @Override public void halfValue(int val) throws RemoteException { Log.d(TAG, "halfValue val="+val/2); } @Override public void doubleValue(int val) throws RemoteException { Log.d(TAG, "doubleValue val="+val*2); } }; @Override public void onCreate() { super.onCreate(); } @Override public void onDestroy(){ super.onDestroy(); } @Override public IBinder onBind(Intent intent) { return myBinder; } }
(05) 定义aidl对应的manifest
manifest内容如下:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.test" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="17" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <service android:name=".MyAIDLService" android:process=":remote"> <intent-filter> <action android:name="com.test.MY_AIDL_SERVICE" /> </intent-filter> </service> </application> </manifest>
至此,我们已经完成了.aidl服务的定义和实现。
2.3 将接口开放给其它应用程序
(06)新建一个工程“AIDLServiceTest”,然后在工程的“com.skywang”包下创建AIDLServiceTest.java;
(07)然后,将MyAIDLInterface.aidl文件拷贝到AIDLServiceTest工程的“com.test”包下。
如下图:
注意:.aidl所在的包名,必须和定义它的包名一样!(即MyAIDLInterface.aidl所在的定义它的工程的包为com.test;那么,调用MyAIDLInterface.aidl的程序,也必须把MyAIDLInterface.aidl放在com.test包下面) (08)AIDLServiceTest.java首先必须实现ServiceConnection接口。
实现ServiceConnection接口的原因是:我们在后面调用.aidl服务的时候,必须通过bindService()去绑定服务;而bindService()需要用到ServiceConnection对象。 实现ServiceConnection很简单,只需要实现两个接口: onServiceConnected —— 连上服务的回调函数。一般在此函数中,获取服务对象。 onServiceDisconnected —— 断开服务的回调函数。可以直接返回null。
ServiceConnection的实现代码如下:
private MyAIDLInterface mBinder = null; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { mBinder = null; } @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.d(TAG, "Service connected!"); mBinder = MyAIDLInterface.Stub.asInterface(service); } };
(09)开始访问服务之前,我们要先通过bindService()绑定服务;使用完毕之后,通过unbindService()断开服务。
AIDLServiceTest.java代码如下:
package com.skywang; import android.app.Activity; 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.content.ComponentName; import android.content.Intent; import android.content.Context; import android.content.ServiceConnection; import com.test.MyAIDLInterface; public class AIDLServiceTest extends Activity { private static final String TAG = "skywang-->AIDLServiceTest"; private Button mStart = null; private Button mHalf = null; private Button mDouble = null; private Button mEnd = null; private MyAIDLInterface mBinder = null; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { mBinder = null; } @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.d(TAG, "Service connected!"); mBinder = MyAIDLInterface.Stub.asInterface(service); } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.aidlservice_test); mStart = (Button) findViewById(R.id.btStart); mStart.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { Log.d(TAG, "click start button"); Intent intent = new Intent("com.test.MY_AIDL_SERVICE"); boolean result = bindService(intent, mConnection, Context.BIND_AUTO_CREATE); if (!result) { mBinder = null; } } }); mHalf = (Button) findViewById(R.id.btHalf); mHalf.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { Log.d(TAG, "click half button"); try { if (mBinder != null) { mBinder.halfValue(10); } } catch (RemoteException e) { e.printStackTrace(); } } }); mDouble = (Button) findViewById(R.id.btDouble); mDouble.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { Log.d(TAG, "click double button"); try { if (mBinder != null) { mBinder.doubleValue(10); } } catch (RemoteException e) { e.printStackTrace(); } } }); mEnd = (Button) findViewById(R.id.btEnd); mEnd.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { Log.d(TAG, "click end button"); if (mBinder != null) { unbindService(mConnection); mBinder = null; } } }); } }
3 示例演示
程序运行效果图:
点击“Start”按钮,Logcat如下: DEBUG/skywang-->AIDLServiceTest(276):click half button DEBUG/skywang-->AIDLServiceTest(276):Service connected! 点击“Half”按钮,Logcat如下: DEBUG/skywang-->AIDLServiceTest(276):click half button DEBUG/skywang-->MyAIDLService(285):halfValue val=5 点击“Double”按钮,Logcat如下: DEBUG/skywang-->AIDLServiceTest(276):click double button DEBUG/skywang-->MyAIDLService(285):doubleValue val=20 点击“End”按钮,Logcat如下: DEBUG/skywang-->AIDLServiceTest(276):click end button
4 参考文献
1. Android API文档:http://developer.android.com/guide/components/aidl.html
2. Android AIDL使用详解:http://blog.csdn.net/stonecao/article/details/6425019
点击下载:源代码
更多service内容:
2 Android Service总结02 service介绍
3 Android Service总结03 之被启动的服务 -- Started Service
4 Android Service总结04 之被绑定的服务 -- Bound Service
5 Android Service总结05 之IntentService