随着Fragment这个类的引 入,Google官方推荐大家使用DialogFragment来代替传统的Dialog.
1,AlertDialog与DialogFragment
before:
AlertDialog dialog = new AlertDialog.Builder(this)
.setTitle("Dialog")
.setMessage("thisis a dialog")
.show();
使用AlertDialog时如果屏幕方向发生变化,就会导致Activity重建,然后之前显示的对话框就不见了.
会产生如下报错:
04-1917:30:06.999: E/WindowManager(14495): Activitycom.example.androidtest.MainActivity has leaked windowcom.android.internal.policy.impl.PhoneWindow$DecorView{42ca3c18 V.E…..R……. 0,0-1026,414} that was originally added here
如果我们想要在旋转屏幕的时候也能保证这个对话框显示就需要做一定的处理了,在activity要销毁前设立一个标志,看这时对话框是否是显示状态,如果是那么activity在下次建立时直接显示对话框。
这么干:
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (dialog != null && dialog.isShowing()) {
outState.putBoolean("DIALOG_SHOWN", true);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState != null) {
boolean isShown = savedInstanceState.getBoolean("DIALOG_SHOWN");
if (isShown) {
AlertDialog dialog = new AlertDialog.Builder(this).setTitle("Dialog")
.setMessage("thisis a dialog").show();
}
}
……
}
after:
若使用DialogFragment,当你旋转屏幕的时候,fragmentManager会自动管理DialogFragment的生命周期.
主要优势是旋转屏幕和按下后退键时可以更好的管理其声明周期;
还可以直接内嵌在activity界面中使用;
次要优势是使用AlertDialog,需要手写监听器positiveListener和negativeListener.代码不简洁.
怎么使用DialogFragment?
创建一个fragment,让其继承自DialogFragment,在onCreatView中通过布局文件建立View.
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
普通的fragment:
fragment是这么使用的:
① 建立FragmentManager对象,用来管理fragment
② 建立fragmentTransaction对象,用来添加和fragment
③ 提交fragment切换(commit)
DialogFragment的show方法里合着用:
public void show(FragmentManager manager, String tag){
mDismissed = false;
mShownByMe = true;
FragmentTransaction ft = manager.beginTransaction(); // creat a fragmentTransaction
ft.add(this, tag); // add fragment with tag
ft.commit();
}
public int show(FragmentTransaction transaction, String tag) {
mDismissed = false;
mShownByMe = true;
transaction.add(this, tag);
mViewDestroyed = false;
mBackStackId = transaction.commit();
return mBackStackId;
}
public void dismiss() {
dismissInternal(false);
}
void dismissInternal(boolean allowStateLoss) {
if (mDismissed) {
return;
}
mDismissed = true;
mShownByMe = false;
if (mDialog != null) {
mDialog.dismiss();
mDialog = null;
}
mViewDestroyed = true;
//一个DialogFragment关闭的时候会检查堆栈里面有没有其他的对象,如果有就pop出来,如果没有就直接remove和commit
if (mBackStackId >= 0) { //如果back stack堆栈有该Dialog,将其pop出来
getFragmentManager().popBackStack(mBackStackId,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
mBackStackId = -1;
} else {
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.remove(this);
if (allowStateLoss) {
ft.commitAllowingStateLoss();
} else {
ft.commit();
}
}
}
信息保存
如果你测试的手机被奇葩的定制了,那就乖乖的保存数据吧。
public class MyDialogFragment extends DialogFragment {
EditText editText;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.dialog, null);
editText = (EditText) rootView.findViewById(R.id.editText);
if (savedInstanceState != null) {
CharSequence text = savedInstanceState.getCharSequence("input data");
editText.setText(text == null ? "" : text);
}
return rootView;
}
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putCharSequence("input data", editText.getText());
super.onSaveInstanceState(outState);
}
}
通过onCreateDialog()来快捷的建立对话框
千万别同时使用onCreatView和onCreatDialog方法,他们仅仅是为了完成同样一个目的的两条路而已。
PS:从生命周期的顺序而言,先执行onCreateDialog(),后执行onCreateView().
在onCreatDialog建立一个警告对话框的builder,通过这个builder的create()方法来生成一个AlertDialog对象,因为AlertDialog是Dialog的子类,所以可以直接返回给Dialog。
public class MyDialogFragment extends DialogFragment implements android.content.DialogInterface.OnClickListener{
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("用户申明")
.setMessage(getResources().getString(R.string.hello_world))
.setPositiveButton("我同意", this)
.setNegativeButton("不同意", this)
.setCancelable(false);
//.show(); // show cann't be use here
return builder.create();
}
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO 自动生成的方法存根
}
}
2,PopupWindow vs. Dialog
[stackoverflow]http://stackoverflow.com/questions/13827138/android-popupwindow-vs-dialogfragment
AlertDialog和Popupwindow的区别:
1)AlertDialog是非阻塞线程的,Popupwindow是阻塞线程的。
2)Dialog没法设置宽为整个屏幕宽,总有点边界。Popupwindow可以。
(1)Popupwindow在显示之前一定要设置宽高,Dialog无此限制。
(2)Popupwindow默认不会响应物理键盘的back,除非显示设置了popup.setFocusable(true);而在点击back的时候,Dialog会消失。
(3)Popupwindow不会给页面其他的部分添加蒙层,而Dialog会。
(4)Popupwindow没有标题,Dialog默认有标题,可以通过dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);取消标题
(5)二者显示的时候都要设置Gravity。如果不设置,Dialog默认是Gravity.CENTER。
(6)二者都有默认的背景,都可以通过setBackgroundDrawable(new ColorDrawable(android.R.color.transparent));去掉。
其中最本质的差别就是:AlertDialog是非阻塞式对话框:AlertDialog弹出时,后台还可以做事情;而PopupWindow是阻塞式对话框:PopupWindow弹出时,程序会等待,在PopupWindow退出前,程序一直等待,只有当我们调用了dismiss方法的后,PopupWindow退出,程序才会向下执行。
Android 官方推荐 : DialogFragment 创建对话框 by HONGYANG on 2014-07-15.
摘自详细解读DialogFragment.
android中Dialog和PopupWindow的区别
Dialog和PopUpWindow的抉择
When to use Android PopupWindow vs Dialog