我有 MediaPlayer 活动。但很多用户不喜欢它,因为异常崩溃:
java.lang.NullPointerException
at android.os.Parcel.readException(Parcel.java:1333)
at android.os.Parcel.readException(Parcel.java:1281)
at android.view.IWindowSession$Stub$Proxy.relayout(IWindowSession.java:634)
at android.view.ViewRootImpl.relayoutWindow(ViewRootImpl.java:3751)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1321)
at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2587)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4424)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)
我无法在我的设备上重现此错误,但根据用户消息,我是一个糟糕的开发人员:))并且在视频播放开始几秒钟后出现此异常。有趣的是,即使在显示错误报告对话框后它仍然可以工作。
在android源代码中寻找原因,我发现它发生在使用iBinder进行事务之后。
mRemote.transact(Stub.TRANSACTION_relayout, _data, _reply, 0);
_reply.readException();
此代码使用在scheduleTraversals方法中调度的Runnable在ViewRootImpl的performTraversalsMethod中执行。而且很难获得它的执行上下文。 ScheduleTraversals 调用了很多方法(invalidate、handleScreenStateChange....)。
有什么想法吗?
发生这种情况是因为我在 Surface 上使用 WindowManager.LayoutParams.FLAG_SCALED。
但是正如我们从android源代码中看到的:http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.3_r2.1/com/android/server/ wm/WindowManagerService.java#2756
if (attrs != null) {
if (win.mAttrs.type != attrs.type) {
throw new IllegalArgumentException(
"Window type can not be changed after the window is added.");
}
flagChanges = win.mAttrs.flags ^= attrs.flags;
attrChanges = win.mAttrs.copyFrom(attrs);
}
//...
final boolean scaledWindow =
((win.mAttrs.flags & WindowManager.LayoutParams.FLAG_SCALED) != 0);
if (scaledWindow) {
// requested{Width|Height} Surface's physical size
// attrs.{width|height} Size on screen
win.mHScale = (attrs.width != requestedWidth) ?
(attrs.width / (float)requestedWidth) : 1.0f;
win.mVScale = (attrs.height != requestedHeight) ?
(attrs.height / (float)requestedHeight) : 1.0f;
} else {
win.mHScale = win.mVScale = 1;
}
从第一个“if”我们看到 attr == null 是正常情况,但是在使用的情况下 scaledWindow 不检查此参数是否为 null。结果我们得到了 NullPointerException。
WindowManager.LayoutParams.FLAG_SCALED 在任何情况下都不应该使用。