Android 自3.0版本引入了DialogFragment这个类,并推荐开发者使用这个类替代之前经常使用的Dialog类,那么DialogFragment相对于之前的Dialog究竟有什么优势呢?这个DialogFragment又该如何使用呢?今天总结一下:

一. 与传统的Dialog类的对比

1.更完善的生命周期管理

之前创建的Dialog的方式如下:

static class MyDialog extends Dialog {

        private String TAG = "xp.chen-Dialog";

        public MyDialog(@NonNull Context context)
{
super(context);
setContentView(R.layout.dialog_normal);
} @Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Log.i(TAG, "onCreate: MyDialog->onCreate()");
} @Override
protected void onStart()
{
super.onStart();
Log.i(TAG, "onStart: MyDialog->onStart()");
} @Override
protected void onStop()
{
super.onStop();
Log.i(TAG, "onStop: MyDialog->onStop()");
} @Override
public void cancel() {
super.cancel();
Log.i(TAG, "cancel: MyDialog->cancel()");
} @Override
public void dismiss()
{
super.dismiss();
Log.i(TAG, "dismiss: MyDialog->dismiss()");
}
}

使用时:

 /**
* Show a normal dialog use Dialog API.
*/
private void showNormalDialog() {
mNormalDialog = new MyDialog(DialogFragmentApiUseDemoActivity.this);
mNormalDialog.show();
}

这样创建本来没什么问题,但是如果这个时候屏幕方向发生变化,就会导致Activity重建,然后之前显示的对话框就消失了,Log上也会报如下错误:

-- ::29.996 -/com.yongdaimi.android.androidapitest E/WindowManager: android.view.WindowLeaked: Activity com.yongdaimi.android.androidapitest.DialogFragmentApiUseDemoActivity has leaked window DecorView@1fa30b4[DialogFragmentApiUseDemoActivity] that was originally added here
at android.view.ViewRootImpl.<init>(ViewRootImpl.java:)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:)
at android.app.Dialog.show(Dialog.java:)
at com.yongdaimi.android.androidapitest.DialogFragmentApiUseDemoActivity.showNormalDialog(DialogFragmentApiUseDemoActivity.java:)
at com.yongdaimi.android.androidapitest.DialogFragmentApiUseDemoActivity.onClick(DialogFragmentApiUseDemoActivity.java:)
at android.view.View.performClick(View.java:)
at android.view.View.performClickInternal(View.java:)
at android.view.View.access$(View.java:)
at android.view.View$PerformClick.run(View.java:)
at android.os.Handler.handleCallback(Handler.java:)
at android.os.Handler.dispatchMessage(Handler.java:)
at android.os.Looper.loop(Looper.java:)
at android.app.ActivityThread.main(ActivityThread.java:)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:)

虽说并不影响使用,程序也不会崩溃,但至少说明这里是有问题的,解决这个问题的办法也很简单,在Activity的onDestory方法中主动关闭:

@Override
protected void onDestroy() {
super.onDestroy();
if (mNormalDialog != null){
mNormalDialog.cancel();
}
Log.e(TAG,"onDestroy");
}

而且如果想在屏幕切换后仍然显示Dialog的话,可以采用如下方法:

在onSaveInstanceState()方法中进行状态的保存:

    @Override
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
Log.i(TAG, "onSaveInstanceState: ");
if (mNormalDialog != null && mNormalDialog.isShowing()) {
outState.putBoolean("DIALOG_SHOWN", true);
}
}

在onCreate()方法对其进行恢复:

@Override
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dialog_fragment_api_use_demo);
initView();
Log.i(TAG, "onCreate: "); if (savedInstanceState != null) {
boolean is_shown = savedInstanceState.getBoolean("DIALOG_SHOWN");
if (is_shown) {
showNormalDialog();
}
} else {
Toast.makeText(this, "savedInstanceState is NULL", Toast.LENGTH_SHORT).show();
}
}

这样就既解决了上面的异常也处理了屏幕方向切换后Dialog消失的问题。但是个人觉得这样很不合理,屏幕旋转是很正常的操作,旋转前旋转后保持一样的界面UI是很正常的事情,要是每次涉及到屏幕旋转都让我做一遍上面的操作,那真的让人抓狂。而且,如果在Activity的onDestory()方法里销毁了Dialog还好,万一忘记销毁了,Dialog里面又有一些复杂操作,还有可能造成内存泄露,所以没办法自动管理Dialog的生命周期是传统Dialog的第一个缺陷。

2. 更合理的功能划分

如果是弹出一个简单的确认取消的对话框,可能直接就在Activity里使用以下方式:

new AlertDialog.Builder(GuideActivity.this).setTitle("用户申明")
.setMessage(getResources().getString(R.string.statement))
.setPositiveButton("我同意", new positiveListener())
.setNegativeButton("不同意", new negativeListener())
.setCancelable(false)
.show();
}private class positiveListener implements DialogInterface.OnClickListener {
@Override
public void onClick(DialogInterface dialog, int which) {
prefs.setIsFirstTime(false);
}
} private class negativeListener implements DialogInterface.OnClickListener {
@Override
public void onClick(DialogInterface dialog, int which) {
Util.virtualHome(GuideActivity.this);
}
}

这倒也没什么不对,对话框也能正常显示 ,可问题是“Activity知道太多了”,你点击对话框上的按钮,那是对话框本身的事情,对话框本身的事情对话框自己知道就好了,Activity没必要知道,上面的onClick()方法里的代码量还算少,多了的话,简直惨不忍睹。

二. DialogFragment的使用

使用上并没有什么特别值得注意的地方,大致和Fragment的使用差不多。以前是在onCreateView()方法里写Fragment的界面,现在在这个方法里写Dialog的界面。

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.dialog_fragment_use_demo, container, false);
return view;
}

另外它还新提供了一个onCreateDialog()的方法,我们可以直接在这个方法里创建传统的Dialog,然后直接返回,很方便。

 @NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState)
{
return super.onCreateDialog(savedInstanceState);
}

显示的话,以前的Dialog是调用show()方法显示的,现在同样是调用show()方法显示,只不过参数有点不同:

/**
* Show a normal dialog use Dialog API.
*/
private void showNormalDialog() {
mNormalDialog = new MyDialog(DialogFragmentApiUseDemoActivity.this);
mNormalDialog.show();
} private void showDialogFragment() {
MyDialogFragment dialogFragment = new MyDialogFragment();
dialogFragment.show(getSupportFragmentManager(), "dialogFragment");
}

我这里分别在代码中使用Dialog和DialogFragment创建了两个对话框,然后在横竖屏切换的时候分别比较两个对话框的状态,并用DialogFragment实现了一个类似iOS上UIActionSheet的效果,代码和效果图如下:

主界面

package com.yongdaimi.android.androidapitest;

import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast; import com.yongdaimi.android.androidapitest.view.MyDialogFragment; public class DialogFragmentApiUseDemoActivity extends AppCompatActivity implements View.OnClickListener
{ private static final String TAG = "xp.chen"; private Button btn_show_dialog_fragment;
private Button btn_show_normal_dialog; private MyDialog mNormalDialog; @Override
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dialog_fragment_api_use_demo);
initView();
Log.i(TAG, "onCreate: ");
/*if (savedInstanceState != null) {
boolean is_shown = savedInstanceState.getBoolean("DIALOG_SHOWN");
if (is_shown) {
showNormalDialog();
}
} else {
Toast.makeText(this, "savedInstanceState is NULL", Toast.LENGTH_SHORT).show();
}*/
} @Override
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
Log.i(TAG, "onSaveInstanceState: ");
/*if (mNormalDialog != null && mNormalDialog.isShowing()) {
outState.putBoolean("DIALOG_SHOWN", true);
}*/
} @Override
protected void onStart()
{
super.onStart();
Log.i(TAG, "onStart: ");
} @Override
protected void onResume()
{
super.onResume();
Log.i(TAG, "onResume: ");
} @Override
protected void onPause()
{
super.onPause();
Log.i(TAG, "onPause: ");
} @Override
protected void onStop()
{
super.onStop();
Log.i(TAG, "onStop: ");
} @Override
protected void onDestroy()
{
super.onDestroy();
Log.i(TAG, "onDestroy: ");
} private void initView()
{
btn_show_dialog_fragment = findViewById(R.id.btn_show_dialog_fragment);
btn_show_dialog_fragment.setOnClickListener(this); btn_show_normal_dialog = findViewById(R.id.btn_show_normal_dialog);
btn_show_normal_dialog.setOnClickListener(this);
} /**
* Show a normal dialog use Dialog API.
*/
private void showNormalDialog() {
mNormalDialog = new MyDialog(DialogFragmentApiUseDemoActivity.this);
mNormalDialog.show();
} private void showDialogFragment() {
MyDialogFragment dialogFragment = new MyDialogFragment();
dialogFragment.show(getSupportFragmentManager(), "dialogFragment");
} @Override
public void onClick(View v)
{
switch (v.getId()) {
case R.id.btn_show_dialog_fragment:
showDialogFragment();
break;
case R.id.btn_show_normal_dialog:
showNormalDialog();
break;
default:
break;
}
} static class MyDialog extends Dialog { private String TAG = "xp.chen-Dialog"; public MyDialog(@NonNull Context context)
{
super(context);
setContentView(R.layout.dialog_normal);
} @Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Log.i(TAG, "onCreate: MyDialog->onCreate()");
} @Override
protected void onStart()
{
super.onStart();
Log.i(TAG, "onStart: MyDialog->onStart()");
} @Override
protected void onStop()
{
super.onStop();
Log.i(TAG, "onStop: MyDialog->onStop()");
} @Override
public void cancel() {
super.cancel();
Log.i(TAG, "cancel: MyDialog->cancel()");
} @Override
public void dismiss()
{
super.dismiss();
Log.i(TAG, "dismiss: MyDialog->dismiss()");
}
} }

DialogFragmentApiUseDemoActivity.java

主界面布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
> <Button
android:id="@+id/btn_show_normal_dialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Show Normal Dialog"
android:textAllCaps="false"
/> <Button
android:id="@+id/btn_show_dialog_fragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Show Dialog Fragment"
android:textAllCaps="false"
/> </LinearLayout>

activity_dialog_fragment_api_use_demo.xml

DialogFragment的对话框:

package com.yongdaimi.android.androidapitest.view;

import android.app.Dialog;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager; import com.yongdaimi.android.androidapitest.R; public class MyDialogFragment extends DialogFragment
{ private static final String TAG = "xp.chen-DialogFragment"; @Override
public void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Log.i(TAG, "onCreate: ");
// setStyle(DialogFragment.STYLE_NO_TITLE, R.style.DialogFullScreen);
} @Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
{
Log.i(TAG, "onCreateView: ");
//去掉dialog的标题,需要在setContentView()之前
this.getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
View view = inflater.inflate(R.layout.dialog_fragment_use_demo, container, false);
return view;
} @NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState)
{
return super.onCreateDialog(savedInstanceState);
} @Override
public void onStart()
{
super.onStart();
Window dialogWindow = getDialog().getWindow();
if (dialogWindow != null) {
dialogWindow.getDecorView().setPadding(0, 0, 0, 0);
dialogWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
WindowManager.LayoutParams lp = dialogWindow.getAttributes();
lp.width = WindowManager.LayoutParams.MATCH_PARENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
lp.gravity = Gravity.BOTTOM;
lp.windowAnimations = android.R.style.Animation_InputMethod;
dialogWindow.setAttributes(lp);
}
} @Override
public void onDetach()
{
super.onDetach();
Log.i(TAG, "onDetach: ");
} @Override
public void onDestroy()
{
super.onDestroy();
Log.i(TAG, "onDestroy: ");
} }

MyDialogFragment.java

对话框布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#F0F0F0"
android:orientation="vertical"> <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:gravity="center"
android:minHeight="50dip"
android:text="请选择指定的类型"
android:textColor="#CCC" /> <Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="1dip"
android:background="@drawable/btn_action_sheet_item_selector"
android:gravity="center"
android:minHeight="44dip"
android:text="ActionSheet 1"
android:textAllCaps="false"
android:textColor="#333"
style="?android:attr/borderlessButtonStyle"
/> <Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="1dip"
android:background="@drawable/btn_action_sheet_item_selector"
android:gravity="center"
android:minHeight="44dip"
android:text="ActionSheet 2"
android:textAllCaps="false"
android:textColor="#333"
style="?android:attr/borderlessButtonStyle"
/> <Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="1dip"
android:background="@drawable/btn_action_sheet_item_selector"
android:gravity="center"
android:minHeight="44dip"
android:text="ActionSheet 3"
android:textAllCaps="false"
android:textColor="#333"
style="?android:attr/borderlessButtonStyle"
/> <Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dip"
android:background="@drawable/btn_action_sheet_item_selector"
android:gravity="center"
android:minHeight="44dip"
android:text="取消"
android:textAllCaps="false"
android:textColor="@android:color/holo_red_light"
style="?android:attr/borderlessButtonStyle"
/> </LinearLayout>

dialog_fragment_use_demo.xml

最终效果:

从图上也能很明显看出,不管屏幕如何切换,使用DialogFragment创建出来的Dialog都能保持原样。

DialogFragment: DialogFragment的一些理解的更多相关文章

  1. Square:从今天開始抛弃Fragment吧!

    原文链接 : Advocating Against Android Fragments 原文作者 : Pierre-Yves Ricau 译文出自 : 开发技术前线 www.devtf.cn 译者 : ...

  2. Android面试二之Fragment

    基本概念 Fragment,简称碎片,是Android 3.0(API 11)提出的,为了兼容低版本,support-v4库中也开发了一套Fragment API,最低兼容Android 1.6. F ...

  3. Fragment(一)--Fragment用法常见问题

    fragment notes fragment相关内容包括 基本定义与使用 回退栈内部实现 fragment通信(与activity 与fragment) DialogFragment VP + Fr ...

  4. 详细解读DialogFragment

    原博客地址:http://www.cnblogs.com/tianzhijiexian/p/4161811.html 相信看这篇文章的人都应该知道android中的Dialog了吧,如果对于Dialo ...

  5. Android 官方推荐 : DialogFragment 创建对话框

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/37815413 1. 概述 DialogFragment在android 3.0时 ...

  6. DialogFragment is gone after returning back from another activity

    基本情景如下: 在DialogFragment中单击一个按钮跳转到another Activity做一些逻辑处理,然后将返回的结果回显到该DialogFragment上. 处理逻辑是: 在Dialog ...

  7. Momo自定义DialogFragment

    在Fragnment弹窗提示 XML <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android&q ...

  8. [Android Pro] Android 官方推荐 : DialogFragment 创建对话框

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/37815413 1. 概述 DialogFragment在android 3.0时 ...

  9. DialogFragment 自定义弹窗

    layout文件 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:a ...

随机推荐

  1. Vim编译器的相关知识

    Vim编译器相关知识 1.关于Vim编译器 在热门Linux操作系统中都会默认安装一款超好用的文本编辑器——名字叫“vim”,vim是vi编辑器的升级版. vim 具有程序编辑的能力,可以主动的以字体 ...

  2. 剑指offer:二维数组的查找

    题目描述 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数 ...

  3. 适用于在线服务的A/B测试方法论

    适用于在线服务的A/B测试方法论 简介: 这篇文章旨在介绍适用于为在线服务进行A/B测试(A/B Test)的方法论.中文网络中目前还缺乏全面的入门级介绍. 我将首先讨论在线服务业进行A/B测试所考虑 ...

  4. kafka,activemq rabbitmq.rocketmq的优点和缺点

    kafka,activemq rabbitmq.rocketmq的优点和缺点: 特性 ActiveMQ RabbitMQ RocketMQ Kafka 单机吞吐量 万级,吞吐量比RocketMQ和Ka ...

  5. HDFS的NameNode中的Namespace管理

    在NameNode中的Namespace管理层是负责管理整个HDFS集群文件系统的目录树以及文件与数据块的映射关系.以下就是Namespace的内存结构: 以上是一棵文件目录树,可见Namespace ...

  6. 机器学习-- 入门demo1 k临近算法

    1.k-近邻法简介 k近邻法(k-nearest neighbor, k-NN)是1967年由Cover T和Hart P提出的一种基本分类与回归方法. 它的工作原理是:存在一个样本数据集合,也称作为 ...

  7. Kubernetes 学习22 kubernetes容器资源需求资源限制及HeapSter(翻车章节)

    一.概述 1.接下来介绍在k8s上运行pod对象时我们如何去监控我们系统级的资源指标以及业务级别的资源指标.数据如何获取和监控.在此之前先介绍一下Pod对象的资源请求和资源限制.即容器的资源需求和资源 ...

  8. 【JS】闭包的理解

    闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无 ...

  9. Linux下安装Phalcon系统环境安装Phalcon 及 安装Phalcon Developer Tools

    一.安装Phalcon Phalcon 需要用的的PHP扩展函数有如下: curl gettext gd2 (to use the Phalcon\Image\Adapter\Gd class) li ...

  10. mapper.xml等资源导入的问题

    在pom.xml中的下导入如下字段 <resources> <resource> <directory>src/main/java</directory> ...