Fragment中的Crash排查
场景
一、在Fragment中getActivity()和getContext()为空
在Fragment的onDetach()方法执行后,在调用getActitity()方法,返回的就是NULL
排查点
- 在
Fragment类中搜索getActivity()和getContext()方法,根据解决方案修改;
解决方案
- 在
Fragment中维护Activity成员变量,代替getActivity()和getContext()的调用; getActivity()必须赋值给一个变量,不能无效判空,例如:
if (getActivity() != null) {
getActivity().getResource();
}
二、在Fragment中getResources()触发not attached to Activity异常
在Fragment中执行异步任务,如果这时候如果Activity触发了重建,那么在异步任务中调用getResources()就会触发not attached to Activity异常,其内部也是调用requireContext()方法
排查点
- 搜索在Fragment异步任务中调用
getResources()的地方;
解决方案
- 在调用
getResources()之前调用isAdded()方法,判断当前Fragment是否添加到了Activity中; - 使用
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;
}
排查点
- 在Fragemnt方法中搜索requireContext()方法;
解决方案
- 捕获异常
IllegalStateException; - 使用
getContext()方法先判断Context是否为NULL;
四、Fragment重建找不到默认构造方法和参数丢失
每一个Fragment必须要有默认的构造函数,使用setArguments方法保存参数。
Constructor used by the default
FragmentFactory. You mustset a custom FragmentFactoryif 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 withgetArguments(). These arguments are automatically saved and restored alongside the Fragment.
在Activity恢复时,会使用默认构造方法重建Fragment,如果没有默认构造函数的话,就会报java.lang.InstantiationException异常
排查点
Fragment类如果自定义了构造方法,必须定义一个默认构造函数;Fragment必须使用setArguments方法保存参数;
解决方案
- 使用
newInstance静态方法
public static FilterPanelFragment newInstance(boolean isAsset) {
Bundle args = new Bundle();
args.putBoolean("isAsset", isAsset);
FilterPanelFragment fragment = new FilterPanelFragment();
fragment.setArguments(args);
return fragment;
}