Fragment中的Crash排查

1,191 阅读2分钟

Fragment中的Crash排查

场景

一、在Fragment中getActivity()和getContext()为空

FragmentonDetach()方法执行后,在调用getActitity()方法,返回的就是NULL

排查点

  1. Fragment类中搜索getActivity()getContext()方法,根据解决方案修改;

解决方案

  1. Fragment中维护Activity成员变量,代替getActivity()getContext()的调用;
  2. getActivity()必须赋值给一个变量,不能无效判空,例如:
if (getActivity() != null) {
    getActivity().getResource();
}
二、在Fragment中getResources()触发not attached to Activity异常

在Fragment中执行异步任务,如果这时候如果Activity触发了重建,那么在异步任务中调用getResources()就会触发not attached to Activity异常,其内部也是调用requireContext()方法

排查点

  1. 搜索在Fragment异步任务中调用getResources()的地方;

解决方案

  1. 在调用getResources()之前调用isAdded()方法,判断当前Fragment是否添加到了Activity中;
  2. 使用getContext()方法先判断Context是否为NULL
三、在Fragment中使用requireContext()方法,触发not attached to Activity异常

requireContext方法如下,在Fragment没有Attach到Activity时,调用该方法会触发异常;

/**
  * Return the {@link Context} this fragment is currently associated with.
  *
  * @throws IllegalStateException if not currently associated with a context.
  * @see #getContext()
  */
@NonNull
public final Context requireContext() {
    Context context = getContext();
    if (context == null) {
        throw new IllegalStateException("Fragment " + this + " not attached to a context.");
    }
    return context;
}

排查点

  1. 在Fragemnt方法中搜索requireContext()方法;

解决方案

  1. 捕获异常IllegalStateException
  2. 使用getContext()方法先判断Context是否为NULL
四、Fragment重建找不到默认构造方法和参数丢失

每一个Fragment必须要有默认的构造函数,使用setArguments方法保存参数。

Constructor used by the default FragmentFactory. You must set a custom FragmentFactory if you want to use a non-default constructor to ensure that your constructor is called when the fragment is re-instantiated.

It is strongly recommended to supply arguments with setArguments(Bundle) and later retrieved by the Fragment with getArguments(). These arguments are automatically saved and restored alongside the Fragment.

Activity恢复时,会使用默认构造方法重建Fragment,如果没有默认构造函数的话,就会报java.lang.InstantiationException异常

排查点

  1. Fragment类如果自定义了构造方法,必须定义一个默认构造函数;
  2. Fragment必须使用setArguments方法保存参数;

解决方案

  1. 使用newInstance静态方法
public static FilterPanelFragment newInstance(boolean isAsset) {
    Bundle args = new Bundle();
    args.putBoolean("isAsset", isAsset);
    FilterPanelFragment fragment = new FilterPanelFragment();
    fragment.setArguments(args);
    return fragment;
}