简介
开发过程中,部分用户(华为 NXT-AL10,华为 MHA AL00等)反馈只要弹框就会崩溃,通过反馈用户的协助,找到日志如下:
java.lang.NullPointerException |
解决
当在自定义Drawable
时,需要注意,如果此Drawable
有可能会被当做背景设置为Window的背景,类似于getWindow().setBackgroundDrawable(BlankDrawable)
,则必须在除了正常的绘制逻辑之外,需要重写Drawable#getConstantState())方法,返回一个不会空的ConstantState对象
解析
从上往下
首先,根据日志,找到最后的崩溃的位置BackdropFrameRenderer#onResourcesLoaded()
:
public class BackdropFrameRenderer extends Thread implements Choreographer.FrameCallback { |
再往上查DecorView#onWindowDragResizeStart()
:
|
可以发现传递到BackdropFrameRenderer
中的resizingBackgroundDrawable
实际是一个DecorView
中的局部变量mResizingBackgroundDrawable
,此时,查找这个局部变量的来源,包括了两个地方:
public void setWindowBackground(Drawable drawable) { |
OK,从最终崩溃向上已经到头了,因为无法确定,到底哪里地方会调用public
方法,所以,从触发的地方查查看。
从下而上
由于触发地方是项目自定义的一个BottomSheetDialog
,初始化代码:
public BottomSheetDialog(Context context, int style) { |
通过getWindow().setBackgroundDrawable(BlankDrawable.getInstance())
往下跟,发现会调用到PhoneWindow
的setBackgroundDrawable(drawable)
方法:
|
而在这个方法中会把这个drawable
设置给DecorView
。OK,对上了。
这个时候,查看下之前使用自定义的Drawable
代码:
/** |
此方法并没有getConstantState()
方法,在起父类Drawable
中:
/** |
查看默认为null。
总结一下,就是在某些特殊情况,特殊机型(问我怎么特殊?我怎么知道,问华为去,┑( ̄Д  ̄)┍),会在某些情况触发了分屏的机制,导致调用到startDragResizing()
从而触发了BackdropFrameRenderer
中的onResourcesLoaded()
而由于自定义的BlankDrawable
并没有重写父类getConstantState()
方法,导致了NPE
综上,修复代码可简单自定义一个内部类实现ConstantState
:
/** |