AIDL (Android(安卓)Interface Definition Language) Android(安卓)接口定义语言
AIDL (Android Interface Definition Language) 是一种接口定义语言,用于生成代码允许Android设备上的两个进程间进程通信(IPC).
如果你需要编写一个进程(比如Activity)访问另一个进程(比如Services)的对象的方法代码,你可以使用AIDL自动生成代码而不用自己配置大量的参数.
AIDL IPC基于接口机制,类似COM,Corba,且更加轻量化.它使用一个代理来在客户和实现间传递值.
Implementing IPC Using AIDL 实现进程通信IPC
分为五个步骤:
1.创建 SomeService.aidl 文件
利用aidl.exe生成接口文件.若你的IDE安装了ADT,将会在gen目录或src相应包中自动根据描述文件生成同名接口文件.否则请手动:
命令行:
adil path\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(IBinder iBinder),它返回接口的实例.
2.实现接口
接口的实现需继承接口.Stub.并实现Stub类的方法.
下面给出一个使用匿名方式实现的例子.
private final SomeService.Stub binder = new SomeService.Stub(){
public void service(){
//...
}
}
注意:
1.没有异常会正常返回
2.RPC通常比较耗时且是异步的,因此应该在线程中调用RPC服务.
3.只支持方法,不支持静态字段.
3.暴露接口给客户
客户要服务,当然要知道在哪有服务.通常一台服务器可能提供不止一个服务.因些,我们使用
RomoteService来管理所有远程服务.
暴露服务必须继承Service.并实现onBind()方法.
- public class RemoteService extends Service{
- ...
- @Override
- public IBinderonBind(Intentintent){
- //Selecttheinterfacetoreturn.Ifyourserviceonlyimplements
- //asingleinterface,youcanjustreturnitherewithoutchecking
- //theIntent.
- if (SomeService. class .getName().equals(intent.getAction())){
- return mBinder;
- }
- if (ISecondary. class .getName().equals(intent.getAction())){
- return mSecondaryBinder;
- }
- return null ;
- }
- /**
- *TheSomeServiceInterfaceisdefinedthroughIDL
- */
- private final SomeService.StubmBinder= new SomeService.Stub(){
- public void registerCallback(SomeServiceCallbackcb){
- if (cb!= null )mCallbacks.register(cb);
- }
- public void unregisterCallback(SomeServiceCallbackcb){
- if (cb!= null )mCallbacks.unregister(cb);
- }
- };
- /**
- *Asecondaryinterfacetotheservice.
- */
- private final ISecondary.StubmSecondaryBinder= new ISecondary.Stub(){
- public int getPid(){
- return Process.myPid();
- }
- public void basicTypes( int anInt, long aLong, boolean aBoolean,
- float aFloat, double aDouble,StringaString){
- }
- };
- }
public class RemoteService extends Service {... @Override public IBinder onBind(Intent intent) { // Select the interface to return. If your service only implements // a single interface, you can just return it here without checking // the Intent. if (SomeService.class.getName().equals(intent.getAction())) { return mBinder; } if (ISecondary.class.getName().equals(intent.getAction())) { return mSecondaryBinder; } return null; } /** * The SomeService Interface is defined through IDL */ private final SomeService.Stub mBinder = new SomeService.Stub() { public void registerCallback(SomeServiceCallback cb) { if (cb != null) mCallbacks.register(cb); } public void unregisterCallback(SomeServiceCallback cb) { if (cb != null) mCallbacks.unregister(cb); } }; /** * A secondary interface to the service. */ private final ISecondary.Stub mSecondaryBinder = new ISecondary.Stub() { public int getPid() { return Process.myPid(); } public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) { } };}
这样暴露好了服务,接着做什么?当然是调用服务了.
调用之前,有必要了解下 对象打包,类似与Java的对象序列化.
4.使用打包传送参数
如果一个类要使用打包功能(类似对象序列化),要实现如下5个步骤:
4.1 实现 Parcelable接口
4.2 实现 public void writeToParcel(Parcel out) 方法
4.3 实现 public void readFromParcel(Parcel in) 方法
4.4 添加一个静态字段 CREATOR 到实现 Parcelable.Creator 接口的类中
4.5 创建一个aidl文件声明你的可打包的类
示例:
Rect.java
- import android.os.Parcel;
- import android.os.Parcelable;
- public final class Rect implements Parcelable{
- public int left;
- public int top;
- public int right;
- public int bottom;
- public static final Parcelable.Creator<Rect>CREATOR= new Parcelable.Creator<Rect>(){
- public RectcreateFromParcel(Parcelin){
- return new Rect(in);
- }
- public Rect[]newArray( int size){
- return new Rect[size];
- }
- };
- public Rect(){
- }
- private Rect(Parcelin){
- readFromParcel(in);
- }
- public void writeToParcel(Parcelout){
- out.writeInt(left);
- out.writeInt(top);
- out.writeInt(right);
- out.writeInt(bottom);
- }
- public void readFromParcel(Parcelin){
- left=in.readInt();
- top=in.readInt();
- right=in.readInt();
- bottom=in.readInt();
- }
- }
import android.os.Parcel;import android.os.Parcelable;public final class Rect implements Parcelable { public int left; public int top; public int right; public int bottom; public static final Parcelable.Creator<Rect> CREATOR = new Parcelable.Creator<Rect>() { public Rect createFromParcel(Parcel in) { return new Rect(in); } public Rect[] newArray(int size) { return new Rect[size]; } }; public Rect() { } private Rect(Parcel in) { readFromParcel(in); } public void writeToParcel(Parcel out) { out.writeInt(left); out.writeInt(top); out.writeInt(right); out.writeInt(bottom); } public void readFromParcel(Parcel in) { left = in.readInt(); top = in.readInt(); right = in.readInt(); bottom = in.readInt(); }}
Rect.aidl
- package android.graphics;
- //DeclareRectsoAIDLcanfinditandknowsthatitimplements
- //theparcelableprotocol.
- parcelableRect;
package android.graphics;// Declare Rect so AIDL can find it and knows that it implements// the parcelable protocol.parcelable Rect;
注意:
参数一定不能越界.
5.调用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().
注解:
你可以使用匿名对象作为参数.
对象是引用计数.
ApiDemos 有个子the Remote Activity 的例子.
- public class RemoteServiceBinding extends Activity{
- /**Theprimaryinterfacewewillbecallingontheservice.*/
- IRemoteServicemService= null ;
- /**Anotherinterfaceweuseontheservice.*/
- ISecondarymSecondaryService= null ;
- ButtonmKillButton;
- TextViewmCallbackText;
- private boolean mIsBound;
- /**
- *Standardinitializationofthisactivity.SetuptheUI,thenwait
- *fortheusertopokeitbeforedoinganything.
- */
- @Override
- protected void onCreate(BundlesavedInstanceState){
- super .onCreate(savedInstanceState);
- setContentView(R.layout.remote_service_binding);
- //Watchforbuttonclicks.
- Buttonbutton=(Button)findViewById(R.id.bind);
- button.setOnClickListener(mBindListener);
- button=(Button)findViewById(R.id.unbind);
- button.setOnClickListener(mUnbindListener);
- mKillButton=(Button)findViewById(R.id.kill);
- mKillButton.setOnClickListener(mKillListener);
- mKillButton.setEnabled( false );
- mCallbackText=(TextView)findViewById(R.id.callback);
- mCallbackText.setText( "Notattached." );
- }
- /**
- *Classforinteractingwiththemaininterfaceoftheservice.
- */
- private ServiceConnectionmConnection= new ServiceConnection(){
- public void onServiceConnected(ComponentNameclassName,
- IBinderservice){
- //Thisiscalledwhentheconnectionwiththeservicehasbeen
- //established,givingustheserviceobjectwecanuseto
- //interactwiththeservice.Wearecommunicatingwithour
- //servicethroughanIDLinterface,sogetaclient-side
- //representationofthatfromtherawserviceobject.
- mService=IRemoteService.Stub.asInterface(service);
- mKillButton.setEnabled( true );
- mCallbackText.setText( "Attached." );
- //Wewanttomonitortheserviceforaslongasweare
- //connectedtoit.
- try {
- mService.registerCallback(mCallback);
- } catch (RemoteExceptione){
- //Inthiscasetheservicehascrashedbeforewecouldeven
- //doanythingwithit;wecancountonsoonbeing
- //disconnected(andthenreconnectedifitcanberestarted)
- //sothereisnoneedtodoanythinghere.
- }
- //Aspartofthesample,telltheuserwhathappened.
- Toast.makeText(RemoteServiceBinding. this ,R.string.remote_service_connected,
- Toast.LENGTH_SHORT).show();
- }
- public void onServiceDisconnected(ComponentNameclassName){
- //Thisiscalledwhentheconnectionwiththeservicehasbeen
- //unexpectedlydisconnected--thatis,itsprocesscrashed.
- mService= null ;
- mKillButton.setEnabled( false );
- mCallbackText.setText( "Disconnected." );
- //Aspartofthesample,telltheuserwhathappened.
- Toast.makeText(RemoteServiceBinding. this ,R.string.remote_service_disconnected,
- Toast.LENGTH_SHORT).show();
- }
- };
- /**
- *Classforinteractingwiththesecondaryinterfaceoftheservice.
- */
- private ServiceConnectionmSecondaryConnection= new ServiceConnection(){
- public void onServiceConnected(ComponentNameclassName,
- IBinderservice){
- //Connectingtoasecondaryinterfaceisthesameasany
- //otherinterface.
- mSecondaryService=ISecondary.Stub.asInterface(service);
- mKillButton.setEnabled( true );
- }
- public void onServiceDisconnected(ComponentNameclassName){
- mSecondaryService= null ;
- mKillButton.setEnabled( false );
- }
- };
- private OnClickListenermBindListener= new OnClickListener(){
- public void onClick(Viewv){
- //Establishacoupleconnectionswiththeservice,binding
- //byinterfacenames.Thisallowsotherapplicationstobe
- //installedthatreplacetheremoteservicebyimplementing
- //thesameinterface.
- bindService( new Intent(IRemoteService. class .getName()),
- mConnection,Context.BIND_AUTO_CREATE);
- bindService( new Intent(ISecondary. class .getName()),
- mSecondaryConnection,Context.BIND_AUTO_CREATE);
- mIsBound= true ;
- mCallbackText.setText( "Binding." );
- }
- };
- private OnClickListenermUnbindListener= new OnClickListener(){
- public void onClick(Viewv){
- if (mIsBound){
- //Ifwehavereceivedtheservice,andhenceregisteredwith
- //it,thennowisthetimetounregister.
- if (mService!= null ){
- try {
- mService.unregisterCallback(mCallback);
- } catch (RemoteExceptione){
- //Thereisnothingspecialweneedtodoiftheservice
- //hascrashed.
- }
- }
- //Detachourexistingconnection.
- unbindService(mConnection);
- unbindService(mSecondaryConnection);
- mKillButton.setEnabled( false );
- mIsBound= false ;
- mCallbackText.setText( "Unbinding." );
- }
- }
- };
- private OnClickListenermKillListener= new OnClickListener(){
- public void onClick(Viewv){
- //Tokilltheprocesshostingourservice,weneedtoknowits
- //PID.Convenientlyourservicehasacallthatwillreturn
- //tousthatinformation.
- if (mSecondaryService!= null ){
- try {
- int pid=mSecondaryService.getPid();
- //Notethat,thoughthisAPIallowsustorequestto
- //killanyprocessbasedonitsPID,thekernelwill
- //stillimposestandardrestrictionsonwhichPIDsyou
- //areactuallyabletokill.Typicallythismeansonly
- //theprocessrunningyourapplicationandanyadditional
- //processescreatedbythatappasshownhere;packages
- //sharingacommonUIDwillalsobeabletokilleach
- //other'sprocesses.
- Process.killProcess(pid);
- mCallbackText.setText( "Killedserviceprocess." );
- } catch (RemoteExceptionex){
- //Recovergracefullyfromtheprocesshostingthe
- //serverdying.
- //Justforpurposesofthesample,putupanotification.
- Toast.makeText(RemoteServiceBinding. this ,
- R.string.remote_call_failed,
- Toast.LENGTH_SHORT).show();
- }
- }
- }
- };
- //----------------------------------------------------------------------
- //Codeshowinghowtodealwithcallbacks.
- //----------------------------------------------------------------------
- /**
- *Thisimplementationisusedtoreceivecallbacksfromtheremote
- *service.
- */
- private IRemoteServiceCallbackmCallback= new IRemoteServiceCallback.Stub(){
- /**
- *Thisiscalledbytheremoteserviceregularlytotellusabout
- *newvalues.NotethatIPCcallsaredispatchedthroughathread
- *poolrunningineachprocess,sothecodeexecutingherewill
- *NOTberunninginourmainthreadlikemostotherthings--so,
- *toupdatetheUI,weneedtouseaHandlertohopoverthere.
- */
- public void valueChanged( int value){
- mHandler.sendMessage(mHandler.obtainMessage(BUMP_MSG,value, 0 ));
- }
- };
- private static final int BUMP_MSG= 1 ;
- private HandlermHandler= new Handler(){
- @Override public void handleMessage(Messagemsg){
- switch (msg.what){
- case BUMP_MSG:
- mCallbackText.setText( "Receivedfromservice:" +msg.arg1);
- break ;
- default :
- super .handleMessage(msg);
- }
- }
- };
- }
更多相关文章
- Android开发——说说Adapter那点事
- Android调用系统相机和图库
- Android实现语音识别
- Android实现图表绘制和展示
- android实现推送实践
- android Activity实现从底部弹出或滑出选择菜单或窗口
- Android(安卓)GPS学习笔记—HAL实现
- Android(安卓)实现QQ第三方登录
- 浅谈Java中Collections.sort对List排序的两种方法