項目中封裝了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()
方法,刪掉它,大功告成。。。