概述
如果我们在 Server 端出现的异常,想让 Client 端知晓,这个要怎么做呢?
验证和分析
现在我们通过一个 ContentProvider 来测试一下这个场景,比如我们在 Server 端抛一个 RuntimeException
异常,发现在 Client 端并未收到这个异常,在 Server 端有下面的日志:
1 | JavaBinder: *** Uncaught remote exception! (Exceptions are not yet supported across processes.) |
那是不是进程间通信不能传递异常呢?开发的经验告诉我们这是不可能的,那究竟是什么原因呢?现在我们通过源码来分析一下:
先从 Server 端的代码分析一下:
1 | @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException |
上面的 Stub 方法是 Binder.execTransact 调用的:
1 | private boolean execTransact(int code, long dataObj, long replyObj, |
可以看到,execTransact
方法已经通过 reply.writeException
写入了 Server端抛出的异常,那为什么 Client 端没有收到呢?再来看一下 Parcel.writeException
方法:
1 | public final void writeException(@NonNull Exception e) { |
看明白了吗?这里只识别到了下面 8 中异常:
- SecurityException
- BadParcelableException
- IllegalArgumentException
- NullPointerException
- IllegalStateException
- NetworkOnMainThreadException
- UnsupportedOperationException
- ServiceSpecificException
如果将上面测试代码抛出的异常换成上面中的一种,那么 Client 端就可以收到了。
再来看一下 Client 代理类的方法:
1 | @Override public boolean hasBook(java.lang.String pkg) throws android.os.RemoteException |
可以看到是可以通过 Parcel.readException
来读取对端的异常的。
1 | private Exception createException(int code, String msg) { |
也是只识别了上面列出的几种异常。
结论
Android 异常的跨进程传递只能是下面 8 种异常:
- SecurityException
- BadParcelableException
- IllegalArgumentException
- NullPointerException
- IllegalStateException
- NetworkOnMainThreadException
- UnsupportedOperationException
- ServiceSpecificException