一次艰难的 NullPointerException 排查

异常信息

Fatal Exception: java.lang.NullPointerException: Attempt to invoke interface method 'void get(Context context) on a null object reference
       at com.snaptube.mixed_list.view.card.MultiSelectCardViewHolder.(Unknown Source)
       at com.snaptube.mixed_list.fragment.MultiSelectFragmentDelegate.onCreateViewHolder(Unknown Source:429)
       at com.snaptube.search.view.YouTubeMultiSelectFragment.onCreateViewHolder(Unknown Source:220)
       at com.snaptube.mixed_list.view.list.MixedAdapter.onCreateViewHolder(Unknown Source:61)
       at android.support.v7.widget.RecyclerView$Adapter.createViewHolder(Unknown Source:6321)
       at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(Unknown Source:5509)
       at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(Unknown Source:5394)
       at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(Unknown Source:5390)
       at android.support.v7.widget.LinearLayoutManager$LayoutState.next(Unknown Source:2149)
       at android.support.v7.widget.LinearLayoutManager.layoutChunk(Unknown Source:1533)
       at android.support.v7.widget.LinearLayoutManager.fill(Unknown Source:1496)
       at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(Unknown Source:593)
       at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(Unknown Source:3537)
       at android.support.v7.widget.RecyclerView.dispatchLayout(Unknown Source:3266)
       at android.support.v7.widget.RecyclerView.consumePendingUpdateOperations(Unknown Source:1603)
       at android.support.v7.widget.RecyclerView$ViewFlinger.run(Unknown Source:4656)
       at android.os.Handler.handleCallback(Handler.java:739)
       at android.os.Handler.dispatchMessage(Handler.java:95)
       at android.os.Looper.loop(Looper.java:145)
       at android.app.ActivityThread.main(ActivityThread.java:6934)
       at java.lang.reflect.Method.invoke(Method.java)
       at java.lang.reflect.Method.invoke(Method.java:372)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)

具体而言,就是说在调用如下方法时,返回 null

public static <T> T get(Context context) {
    return (T) context.getSystemService(SERVICE_NAME);
  }

这个方法定义在 DaggerService 中:

public class DaggerService {
  public static final String SERVICE_NAME = DaggerService.class.getName();

  public DaggerService() {
  }

  public static <T> T get(Context context) {
    return (T) context.getSystemService(SERVICE_NAME);
  }
}

既然问题已经定位,就需要排查原因了,可能原因如下:

  1. context 类型不符,即 context 不为 Activity/Application 类型,这时会导致 context.getSystemService() 方法中没有我们自定义的 SERVICE_NAME 方法,从而导致 context.getSystemService() ;
  2. context 为 Activity/Application 类型,这时就是因为由于我们自己的 getSystemService() 内部逻辑输出 null;

根据分析,要定位具体原因的话,需要按如下步骤进行处理:

  1. 判断 context 类型,若 context 不为 Activity/Application 类型,那么说明问题产生的原因为“传入了一个错误的 context 类型”;
  2. 若 context 为 Activity 类型,则查看在哪些情况下,BaseActivity 的 getSystemService 返回 null;
  3. 若 context 为 Application 类型,则查看在哪些情况下,BaseApplication 的 getSystemService 返回 null。

打日志显示获得的 Context 为 Activity 类型,所以现在只需要查看在什么情况下 BaseActivity 的 getSystemService 会返回 null 即可。查阅源码,我们发现 BaseActivity 的 getSystemService 代码如下:

public Object getSystemService(@NonNull String name) {
    if (DaggerService.SERVICE_NAME.equals(name)) {
      return activityComponent;
    }
    return null;
  }

同时在 BaseActivity 的 onDestory 方法中会将 activityComponent 置为 null,所以当 Activity 的 destory 方法调用后,activityComponent 就会返回 null,而我们的应用场景为,在 onLoadMore 方法中加载数据,然后数据加载完成后获取该 activityComponent,并更新主界面,因为数据加载为耗时操作,所以很有可能数据还未加载完成,所在的 Activity 已经由于某种原因被销毁了,此时就会出现 NPE,解决办法为在 RxJava 的事件流中添加 Activity 生命周期绑定,确保在 onDestory 方法被调用后不再进行后续操作。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 176,460评论 25 709
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 11,893评论 0 17
  • Android Studio JNI流程首先在java代码声明本地方法 用到native关键字 本地方法不用去实现...
    MigrationUK阅读 14,096评论 7 123
  • 2014第二学期悦知读者协会活动策划方案 本协会秉持共同学习的宗旨,现对于2014第二学期相关活动作如下计划: 一...
    爾酥阅读 1,648评论 0 1
  • 生词表 使用场景 在实际开发中,需要开启N个异步线程,但是后续操作,需要依赖N个线程返回的数据,需要接收所有线程任...
    c5f8c453b41e阅读 7,926评论 0 3

友情链接更多精彩内容