美文网首页
一次艰难的 NullPointerException 排查

一次艰难的 NullPointerException 排查

作者: LilacZiyun | 来源:发表于2017-08-30 22:31 被阅读199次

异常信息

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 方法被调用后不再进行后续操作。

相关文章

网友评论

      本文标题:一次艰难的 NullPointerException 排查

      本文链接:https://www.haomeiwen.com/subject/wreadxtx.html