关于使用AIDL出现空指针的解决办法

使用AIDL进行远程调用的时候出现的空指针异常,解决过程稍微有点小曲折。具体安下

1.先贴异常信息

1 ERROR/AndroidRuntime(9435): FATAL EXCEPTION: main
2 ERROR/AndroidRuntime(9435): java.lang.NullPointerException
3 ERROR/AndroidRuntime(9435): at android.os.Parcel.readException(Parcel.java:1328)
4 ERROR/AndroidRuntime(9435): at android.os.Parcel.readException(Parcel.java:1276)

2.解析原因:看调用栈显示的是android.os.Parcel.readException位置出现了空指针异常,但是这是源代码啊,这里怎么会出空指针异常呢。好吧,要本看源码了:

 1 public final void readException(int code, String msg) {
 2         switch (code) {
 3             case EX_SECURITY:
 4                 throw new SecurityException(msg);
 5             case EX_BAD_PARCELABLE:
 6                 throw new BadParcelableException(msg);
 7             case EX_ILLEGAL_ARGUMENT:
 8                 throw new IllegalArgumentException(msg);
 9             case EX_NULL_POINTER:
10                 throw new NullPointerException(msg);
11             case EX_ILLEGAL_STATE:
12                 throw new IllegalStateException(msg);
13         }
14         throw new RuntimeException("Unknown exception code: " + code
15                 + " msg " + msg);
16     }

上面是出错的位置的代码。傻眼了,原来不是哪里有引用了空对象,而是它抛出了一个空指针异常。这是什么情况呢?

3.接着分析原因:追查readException方法调用的地方

 1 @Override public java.lang.String doOperation() throws android.os.RemoteException
 2 {
 3 android.os.Parcel _data = android.os.Parcel.obtain();
 4 android.os.Parcel _reply = android.os.Parcel.obtain();
 5 java.lang.String _result;
 6 try {
 7 _data.writeInterfaceToken(DESCRIPTOR);
 8 mRemote.transact(Stub.TRANSACTION_getMaxCpuFreq, _data, _reply, 0);
 9 _reply.readException();
10 _result = _reply.readString();
11 }
12 finally {
13 _reply.recycle();
14 _data.recycle();
15 }
16 return _result;
17 }

关键代码是_reply.readException(); _reply为mRemote.transact()方法执行后的返回数据对象,即_reply为远程接口返回的数据封装对象。但是通过log查看,远程接口方法并没有执行完成啊,并没有返回数据啊,那怎么会有返回数据呢,而且返回通过返回数据对象抛出了空指针异常?

4.继续分析原因:由上可知远程方法并没有执行完成,但是transact方法却执行完成了,并且通过返回数据对象抛出了空指针,说明远程接口的api里面的实现是有问题的,它的问题导致了远程方法没有执行完成,直接返回。但是现在问题又来了,由于没有错误日志,没有调用栈信息,如果快速知道远程接口哪里代码出问题了呢。正在困惑的时候看到了国外的网站上给出了解决办法:

在远程实现接口的时候,实现onTransact方法,然后在里面捕获异常,并打印出调用栈的信息:

1 protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
2     try {
3         super.onTransact(code, data, reply, flags);
4     } catch (RuntimeException e) {
5         Log.w("MyClass", "Unexpected remote exception", e);
6         throw e;
7     }
8 }

原来是出现的exception是远端api实现中抛出来的,然后直接返回,将异常结果抛给了调用远端程序的客户端,原来如此。然后借助上面的调试代码打出的堆栈信息,直接定位,解决问题。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android AIDL(Android Interface Definition Language)是一种用于定义客户端和服务之间通信接口的语言。AIDL 是一个 Android 特有的 RPC(远程过程调用)机制。 下面是使用 AIDL 的基本步骤: 1. 定义 AIDL 接口 在服务端创建一个 AIDL 文件,定义服务的接口方法。例如,创建一个名为 IMyService.aidl 的文件,其中包含以下内容: ``` interface IMyService { void sayHello(); } ``` 2. 实现 AIDL 接口 在服务端实现 AIDL 接口,例如: ``` public class MyService extends Service { private final IMyService.Stub binder = new IMyService.Stub() { @Override public void sayHello() throws RemoteException { Log.i("MyService", "Hello World"); } }; @Nullable @Override public IBinder onBind(Intent intent) { return binder; } } ``` 3. 绑定服务 在客户端绑定服务,例如: ``` private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { IMyService myService = IMyService.Stub.asInterface(service); try { myService.sayHello(); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } }; private void bindService() { Intent intent = new Intent(this, MyService.class); bindService(intent, connection, Context.BIND_AUTO_CREATE); } ``` 通过上述步骤,就可以实现客户端与服务端之间的通信。需要注意的是,AIDL 接口中定义的方法必须是可序列化的。如果方法参数或返回值类型不支持序列化,可以通过 Parcelable 接口实现序列化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值