1. 你现在的执行顺序
PopupWindow 调用 setPanelData →
mWebPanelImpl = new NadWebPanelHandler(...);进入NadWebPanelHandler构造方法:
mPanelBrowserView = NadWebPanelRuntime.getPanelBrowserViewCreator().createWebPanelContainer(activity);mPanelScrollView = new PanelScrollView(activity);← 现在是在这里构造的 PanelScrollView
PanelScrollView构造方法里:
public PanelScrollView(Context context) {
super(context);
initScrollContainer(); // 这里你直接调
}如果你在initScrollContainer()里立刻调用keyboardListener(),就会进入:
mNadWebPanelContainer.getWindowVisibleDisplayFrame(windowRect);但是这时候mNadWebPanelContainer还是 null
2. 为什么它是 null?
关键是:
mNadWebPanelContainer不是mPanelBrowserView本身,而是PanelScrollView里的一个成员,它的赋值(findViewById 或 addView)是在更晚的地方才发生的——initBrowserContainer() 里。
看你的代码,在 NadWebPanelHandler.createPanelView() 中才有:
mPanelScrollView?.initBrowserContainer(it, listener)
rootView.addView(it, layoutParams)这时候:
initBrowserContainer()才会把mNadWebPanelContainer赋值addView()才把整个PanelScrollView放进 View 树
所以在构造 PanelScrollView → initScrollContainer() → keyboardListener() 的时机,
mNadWebPanelContainer 还没被初始化,直接用就 NPE 了。
3. 为什么放到 onPreDraw 不会 NPE?
因为 onPreDraw 触发的时机已经是:
createPanelView()完成(mPanelBrowserView已加进mPanelScrollView)initBrowserContainer()执行过(mNadWebPanelContainer已赋值)- 整个 View 树完成 measure/layout
所以那时候mNadWebPanelContainer一定非空。
4. 总结一下
你“以为不会 NPE”是因为看到了mPanelBrowserView先于mPanelScrollView创建,
但mNadWebPanelContainer并不是 mPanelBrowserView,它的赋值逻辑晚得多。
构造 PanelScrollView 时它还是 null,直到initBrowserContainer()才赋值。
为什么你这段代码里 onPreDraw 是安全的
你的调用链是:
createPanelView()
→ initBrowserContainer()
→ onCreateBrowserContainer()
→ addView(frameLayout) // 给 PanelScrollView 加子 ViewonPreDraw触发的时候:
- 这个
frameLayout已经是mNadWebPanelContainer addView()已完成并同步加入子 View 列表- 本帧 measure/layout 也已跑过
调用addView()时,会触发一次requestLayout(),请求重新布局。onPreDraw 在每帧都会触发一次,并且永远在 addView 之后,这是由 Android 的绘制时序保证的。
这块有点绕,总结一下就是 addView 才会触发 onPreDraw。而我们是在
initBrowserContainer做 addView,所以 onPreDraw 时,肯定执行了initBrowserContainer,这时候就赋值了,因此不会 NPE。实际上和 addView 关系不大,只是 addView 时,保证了mNadWebPanelContainer不为空。
更新: 2025-08-13 10:08:36
原文: https://www.yuque.com/dongpozhouzi-mshe3/zhm85g/rhl5pyq8tspmcvdc