AIDL总结

本文详细介绍了 Android 进程间通信(IPC)的重要组件 AIDL 的使用方法与注意事项,包括接口定义规范、异常处理机制等内容。

AIDL定义时的注意事项:

(1)接口名和aidl文件名相同.

(2)接口和方法前不用加访问权限修饰符public,private,protected等,也不能用final,static.

(3)AIDL默认支持的类型包话java基本类型(int,long,boolean等)和(String,List,Map,CharSequence),使用这些类型时不需要import声明.对于List和Map中包含的元素类型必须是AIDL支持的类型.如果使用自定义类型作为参数或返回值,自定义类型必须实现Parcelable接口.

(4)自定义类型和AIDL生成的其它接口类型在aidl描述文件中,应该显式import,即使在同一个包中.

(5)在aidl文件中所有非Java基本类型参数必须加上in、out、inout标记,以指明参数是输入参数、输出参数还是输入输出参数.

(6)Java原始类型默认的标记为in,不能为其它标记.

(7)oneway 关键字的使用:当接口使用oneway关键字修饰时,表示接口在远程调用时是不会block的,即接口调用时发送完transaction数据后立即返回而不会等待远端的结果。注意,这只针对IPC的调用,同样的接口如果是在同一进程内部被调用的话,oneway关键字不起任何效果,方法该阻塞就阻塞。

         

AIDL只支持接口方法,不能公开static变量。


抛出的异常是不能返回给调用者(跨进程抛异常处理是不可取的)。但是如果服务端有异常,客户端会收到RemoteException??


关于RemoteException,在StackOverflow上有一段讲述:

http://stackoverflow.com/questions/3156389/android-remoteexceptions-and-services

These exceptions do indeed get thrown and you should write appropriate try/catch logic to handle the situation where a remote method you invoked on a service did not complete.

As far as your investigation, you were on the right track looking through the native sources. What you may have overlooked is thatandroid.os.RemoteException is a actually just a base class for other Binder related exceptions and that it is a subclass,android.os.DeadObjectException, which is thrown within the native code of Binder.

An activity will see this exception if it makes use of a service running in another process that dies in the middle of performing a request. I was able to prove this to myself by making the following minor changes toMarko Gargenta's AIDLDemo example.

First, make sure the service runs in its own process by updating the AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.marakana" android:versionCode="1" android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name"
        android:theme="@android:style/Theme.Light">
        <activity android:name=".AIDLDemo" android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <!--ADD THE android:process TAG TO THE SERVICE-->
        <service android:name=".AdditionService" android:process=":process2"/>
    </application>
    <uses-sdk android:minSdkVersion="3" />
</manifest>


Then modify the add method to exit prematurely:

@Override
public IBinder onBind(Intent intent) {

    return new IAdditionService.Stub() {
        /**
         * Implementation of the add() method
         */
        public int add(int value1, int value2) throws RemoteException {
            Log.d(TAG, String.format("AdditionService.add(%d, %d)", value1,
                    value2));

            System.exit(-1); // KILL THE PROCESS BEFORE IT CAN RESPOND

            return value1 + value2;
        }

    };
}

In logcat you see the service process die, the activity receive a DeadObjectException, and ultimately the system respawn the service process.

D/AdditionService( 1379): AdditionService.add(1, 1)
I/AndroidRuntime( 1379): AndroidRuntime onExit calling exit(-1)
D/Zygote  (   32): Process 1379 exited cleanly (255)
I/ActivityManager(   58): Process com.marakana:process2 (pid 1379) has died.
W/ActivityManager(   58): Scheduling restart of crashed service com.marakana/.AdditionService in 5000ms
D/AIDLDemo( 1372): onClick failed with: android.os.DeadObjectException
W/System.err( 1372): android.os.DeadObjectException
W/System.err( 1372):    at android.os.BinderProxy.transact(Native Method)
W/System.err( 1372):    at com.marakana.IAdditionService$Stub$Proxy.add(IAdditionService.java:95)
W/System.err( 1372):    at com.marakana.AIDLDemo$1.onClick(AIDLDemo.java:81)
W/System.err( 1372):    at android.view.View.performClick(View.java:2408)
W/System.err( 1372):    at android.view.View$PerformClick.run(View.java:8816)
W/System.err( 1372):    at android.os.Handler.handleCallback(Handler.java:587)
W/System.err( 1372):    at android.os.Handler.dispatchMessage(Handler.java:92)
W/System.err( 1372):    at android.os.Looper.loop(Looper.java:123)
W/System.err( 1372):    at android.app.ActivityThread.main(ActivityThread.java:4627)
W/System.err( 1372):    at java.lang.reflect.Method.invokeNative(Native Method)
W/System.err( 1372):    at java.lang.reflect.Method.invoke(Method.java:521)
W/System.err( 1372):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
W/System.err( 1372):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
W/System.err( 1372):    at dalvik.system.NativeStart.main(Native Method)
D/AIDLDemo( 1372): onServiceDisconnected() disconnected
I/ActivityManager(   58): Start proc com.marakana:process2 for service com.marakana/.AdditionService: pid=1399 uid=10037 gids={1015}
D/AdditionService( 1399): onCreate()
D/AIDLDemo( 1372): onServiceConnected() connected

I would imagine if your service was running in the same process as your activity you might never see this exception but then again if that were the case you probably wouldn't be bothering with AIDL.

Additionally, as you discovered, Android does not tunnel exceptions between processes. If you need to communicate an error back to a calling activity then you need to use other means
### AIDL 的基本概念 AIDL(Android Interface Definition Language)是一种接口定义语言,主要用于在 Android 中实现跨进程通信(IPC)。通过 AIDL,开发者可以定义客户端和服务端之间的交互协议,并自动生成必要的代码来处理底层的 IPC 细节。 --- ### AIDL 文件结构与生成机制 当开发人员创建一个 `.aidl` 文件时,Android SDK 工具会在编译过程中将其转换为对应的 Java 接口文件[^3]。此接口文件包含了一个名为 `Stub` 的内部静态抽象类,该类继承自 `android.os.Binder` 并实现了由 `.aidl` 文件所定义的方法[^1]。具体来说: - **Stub 类的作用**:它是一个 Binder 实现的具体形式,允许服务端绑定到远程对象并提供方法调用支持。 - **Binder 框架**:`Binder` 是 Android 系统的核心组件之一,负责管理不同进程间的通信通道。 以下是典型的 AIDL 文件及其生成逻辑的一个简单例子: #### AIDL 文件示例 ```aidl // IRemoteInterface.aidl package com.tpv.app.aidldemo; interface IRemoteInterface { void basicType(int anInt, long aLong, boolean aBoolean, double aDouble, String aString); } ``` #### 自动生成的 Java 接口 ```java public interface IRemoteInterface extends android.os.IInterface { public static abstract class Stub extends android.os.Binder implements IRemoteInterface { } void basicType(int anInt, long aLong, boolean aBoolean, double aDouble, String aString); } ``` 上述过程展示了如何利用 AIDL 来简化复杂的数据传输操作以及多线程环境中的同步问题。 --- ### 创建与使用 AIDL 文件 为了方便管理和组织项目资源,在 Android Studio 中新建 AIDL 文件通常位于专门的 aidl 文件夹下[^2]。这个文件夹的位置一般设置成与 src/main/java 同级,并且其中的包命名空间需匹配项目的 applicationId 设置。这样做的好处是可以保持良好的目录层次关系,便于维护和扩展功能模块。 一旦完成编写 .aidl 文件之后,就可以按照常规方式启动 Service 或者其他后台任务单元,并暴露给外部访问点。对于客户端而言,则需要借助于特定 API 将 IBinder 对象转化为目标类型的实例以便进一步调用相关成员函数[^4]。 下面给出一段简单的代码片段说明这一流程: #### 服务端实现 ```java public class MyService extends Service { private final IRemoteInterface.Stub binder = new IRemoteInterface.Stub() { @Override public void basicType(int anInt, long aLong, boolean aBoolean, double aDouble, String aString) throws RemoteException { // 方法体... } }; @Nullable @Override public IBinder onBind(Intent intent) { return binder; } } ``` #### 客户端连接 ```java IRemoteInterface remoteInterface = IRemoteInterface.Stub.asInterface(service); remoteInterface.basicType(10, 100L, true, 3.14d, "Test"); ``` 以上两部分共同构成了基于 AIDL 技术的服务请求模式。 --- ### 总结 综上所述,AIDL 提供了一种强大而又灵活的方式来进行 Android 应用间或者应用内的异构通讯需求解决办法。通过对指定格式描述符解析后产生的代理类能够有效屏蔽掉繁琐的消息传递细节从而让程序员专注于业务逻辑本身之上[^2]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值