项目中封装了BaseDialogFragment
,但是在androidx
从1.0.0升级到1.1.0之后每次弹窗都会crash。那么首先猜测肯定是DialogFragment
在1.1.0的时候做了修改,找茬开始。
BaseDialogFragment
public abstract class BaseDialogFragment extends DialogFragment implements View.OnClickListener {
protected View mRootView;
private Context mContext;
private boolean isShowing = false;
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
initLayout();
mRootView = inflater.inflate(getLayoutId(), container, false);
mContext = mRootView.getContext();
return mRootView;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (initExtraData()) {
initView();
initData(); //initData中 初始化 Presenter
initListener();
loadData();
} else {
dismiss();
}
}
/**
* 返回布局id R.layout.main
*
* @return
*/
//返回布局id R.layout.main
protected abstract int getLayoutId();
/**
* 初始化通过bundle传过来的数据
* getArguments().getString() etc.
*/
//初始化通过bundle传过来的数据
protected boolean initExtraData() {
return true;
}
protected void initView() {
}
protected void initListener() {
}
protected void initData() {
}
protected void loadData() {
}
//IllegalStateException : Can not perform this action after onSaveInstanceSate
//ShowMedalDialogFragment 必须重写改方法 trycatch一下
@Override
public void show(FragmentManager manager, String tag) {
try {
if (!isShowing) {
isShowing = true;
super.show(manager, tag);
}
} catch (Throwable ignore) {
}
}
@Override
public void dismiss() {
try {
dismissAllowingStateLoss();
} catch (Exception e) {
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
}
protected View findViewById(int id) {
if (mRootView == null) {
return null;
} else {
return mRootView.findViewById(id);
}
}
@Override
public Context getContext() {
return mContext;
}
//region 弹窗布局初始化
protected void initLayout() {
Window window = null;
Dialog dialog = getDialog();
if (dialog == null) {
return;
}
window = getDialog().getWindow();
if (window != null) {
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
window.setGravity(dialogGravity());
window.requestFeature(Window.FEATURE_NO_TITLE);
window.setWindowAnimations(windowAnimations());
getDialog().getWindow().getDecorView().setPadding(0, 0, 0, 0);
dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
@Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
return keyCode == KeyEvent.KEYCODE_BACK && !cancelable();
}
});
dialog.setCancelable(cancelable()); //点击返回键对话框消失
dialog.setCanceledOnTouchOutside(canCanceledOnTouchOutside()); //点击dialog以外区域对话框消失
// 设置宽度为屏宽、靠近屏幕底部。
WindowManager.LayoutParams wlp = window.getAttributes();
wlp.width = dialogWidth();
wlp.height = dialogHeight();
//背景是否透明
if (isBackgroundTransparent()) {
wlp.dimAmount = 0.0f;
}
window.setAttributes(wlp);
}
}
/**
* 点击返回键对话框消失,默认为不可以
*
* @return
*/
protected boolean cancelable() {
return false;
}
/**
* 点击dialog以外区域对话框消失,默认不可以
*
* @return
*/
protected boolean canCanceledOnTouchOutside() {
return false;
}
/**
* dialog进入动画,默认无动画
*
* @return
*/
protected int windowAnimations() {
// R.style.anim_person_info_enter_exit
return 0;
}
/**
* dialog 宽度
*
* @return
*/
protected int dialogWidth() {
return WindowManager.LayoutParams.MATCH_PARENT;
}
/**
* dialog 位置
*
* @return
*/
protected int dialogHeight() {
return WindowManager.LayoutParams.MATCH_PARENT;
}
/**
* dialog 高度
*
* @return
*/
protected int dialogGravity() {
return Gravity.CENTER;
}
/**
* dialog 背景是否透明
*
* @return
*/
protected boolean isBackgroundTransparent() {
return false;
}
//endregion 弹窗布局初始化
protected OnDismissListener onDismissListener;
@Override
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
isShowing = false;
if (onDismissListener != null) {
onDismissListener.onDismiss(dialog);
}
}
public BaseDialogFragment setOnDismissListener(OnDismissListener onDismissListener) {
this.onDismissListener = onDismissListener;
return this;
}
public interface OnDismissListener {
void onDismiss(DialogInterface dialog);
}
@Override
public void onClick(View v) {
}
}
查看了源码,没有发现有什么不同呀,主要是代码太多了,是在看不下去了。就去看了看更新文档,还是没发现有提到对DialogFragment
有做处理的。 我太难了!我就不信了找不到问题。然后又继承直接继承DialogFragment
实现了Dialog
。没有任何问题,一切正常运行。那么问题就可以确定是封装的BaseDialogFragment
有问题了。我一行代码一行代码的尝试,终于在我注释掉getContext()
方法的时候不会Crash了。哇,终于找到了。对于我这样一个好学的人来说,那我必须用弄懂是为什么会这样啊。然后我就去看调用getContext()
并且会报出Crash的错误信息的代码。
@NonNull
public final Context requireContext() {
Context context = getContext();
if (context == null) {
throw new IllegalStateException("Fragment " + this + " not attached to a context.");
}
return context;
}
就是这个地方,那么什么地方用到这个方法了呢?上代码。
androidx 1.1.0
@NonNull
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
return new Dialog(requireContext(), getTheme());
}
就是这个地方,同时我又去看了1.0.0的代码,发现了一个天大的秘密
androidx 1.0.0
@NonNull
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
return new Dialog(getActivity(), getTheme());
}
没错,就是1.1.0的创建Dialog
的时候第一个参数从getActivity()
改成了requireContext()
。但是封装的BaseDialogFragment
重写了getContext()
方法,在执行onCreateDialog()
的时候还没有执行onCreateView()
,所以获取到的context
为null
,这就找到原因了。其实看了一下根本没必要重写getContext()
方法,删掉它,大功告成。。。