Choreographer.java第966行空指针崩溃原因排查
崩溃定性结论
这个崩溃不属于Android系统原生问题,绝大多数情况由业务代码操作列表控件时序不当引发,仅极低概率为低版本官方依赖库的未修复缺陷。
崩溃核心报错:
Fatal Exception: java.lang.NullPointerException
Attempt to invoke virtual method 'android.view.ViewGroup$LayoutParams android.view.View.getLayoutParams()' on a null object reference
触发链路说明
完整崩溃调用栈如下:
androidx.recyclerview.widget.OrientationHelper$2.getDecoratedStart (OrientationHelper.java:403) androidx.leanback.widget.GridLayoutManager.getViewMin (GridLayoutManager.java:1159) androidx.leanback.widget.GridLayoutManager$2.getEdge (GridLayoutManager.java:1746) androidx.leanback.widget.Grid.removeInvisibleItemsAtEnd (Grid.java:416) androidx.leanback.widget.GridLayoutManager.removeInvisibleViewsAtEnd (GridLayoutManager.java:1840) androidx.leanback.widget.GridLayoutManager.scrollDirectionPrimary (GridLayoutManager.java:2473) androidx.leanback.widget.GridLayoutManager.scrollVerticallyBy (GridLayoutManager.java:2415) androidx.recyclerview.widget.RecyclerView.scrollStep (RecyclerView.java:1972) androidx.recyclerview.widget.RecyclerView$ViewFlinger.run (RecyclerView.java:5476) android.view.Choreographer$CallbackRecord.run (Choreographer.java:966) android.view.Choreographer.doCallbacks (Choreographer.java:790) android.view.Choreographer.doFrame (Choreographer.java:721) android.view.Choreographer$FrameDisplayEventReceiver.run (Choreographer.java:951) android.os.Handler.handleCallback (Handler.java:883) android.os.Handler.dispatchMessage (Handler.java:100) android.os.Looper.loop (Looper.java:214) android.app.ActivityThread.main (ActivityThread.java:7356) java.lang.reflect.Method.invoke (Method.java) com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:492) com.android.internal.os.ZygoteInit.main (ZygoteInit.java:930)
- 崩溃发生在RecyclerView惯性滑动的帧渲染回调中:
RecyclerView$ViewFlinger是RecyclerView处理惯性滑动的内部类,由Choreographer的vsync信号调度执行,属于异步渲染流程,业务层的直接调用栈已经出栈,因此日志中不会显示业务类名,这是滑动时序类崩溃的典型特征,不能以此判定为系统问题。 - 直接触发点:Leanback库的GridLayoutManager执行尾部不可见Item回收逻辑时,遍历拿到的子View引用为null,调用
getLayoutParams()时触发空指针。
高频根因排序
- 占比最高:在非主线程修改Adapter数据源、调用
notifyDataSetChanged/notifyItemRemoved等刷新方法,导致LayoutManager滑动遍历子View时,内部维护的子View列表和实际数据状态不一致,拿到已经被移除的null引用。 - 次高频:在RecyclerView的
onScrolled/onScrollStateChanged滑动回调中直接增删Item、刷新列表,和LayoutManager正在执行的滚动回收逻辑产生时序冲突。 - 容易忽略的场景:自定义ItemAnimator存在逻辑缺陷,动画执行过程中提前将Item从视图树detach,导致LayoutManager遍历不到有效View。
- 低版本库问题:若项目使用的
androidx.leanback:leanback版本低于1.1.0-rc01,该版本前GridLayoutManager确实存在子View遍历未做空判断的已知缺陷,升级依赖即可排除库本身问题。
修复排查步骤
- 全局检索所有使用Leanback GridLayoutManager的列表页面,排查所有修改Adapter数据、调用notify系列刷新方法的代码,确保所有刷新逻辑都在主线程执行,禁止子线程直接操作列表数据。
- 若业务需要在滑动过程中触发列表数据变更,先判断RecyclerView滑动状态,等滑动状态变为
SCROLL_STATE_IDLE(停止滑动)后再执行数据刷新,避免在惯性滑动过程中直接操作列表。 - 将leanback依赖升级到项目适配的最新稳定版本,排除低版本库自身的判空缺失问题。
- 若列表使用了自定义ItemAnimator,临时替换为系统默认ItemAnimator复现验证,排查自定义动画的时序问题。
内容的提问来源于stack exchange,提问作者vivek mohod
相关产品推荐
相关产品推荐

