Fragment是在Android 3.0提出的,为了兼容低版本,support-v4库也提供了一套Fragment 的API,这也是官方推荐使用的。Fragment依赖于Activity,通常用Fragment来构建UI和适配大小屏幕,其有自己的生命周期。本文主要介绍Fragment生命周期以及在DialogFragment中的应用。
Fragment生命周期
Fragment的生命周期和Activity生命周期有点相似,直接上图:
1.onAttach():在片段已与 Activity 关联时调用。
2.onCreate():系统会在创建片段时调用此方法。我们可以在此初始化想在片段暂停或停止后恢复时保留的必需片段组件。
3.onCreatView():系统会在片段首次绘制其用户界面时调用此方法。要想为片段绘制 UI,从此方法中返回的 View 必须是片段布局的根视图。
4.onResume():片段可见可交互时调用;
5.onPause():系统将此方法作为用户离开片段的第一个信号(但并不总是意味着此片段会被销毁)进行调用。 通常应该在此方法内确认在当前用户会话结束后仍然有效的任何更改(因为用户可能不会返回)。
6.onStop():当Fragment不可见时调用。
7.onActivityCreated():在 Activity 的 onCreate() 方法已返回时调用。
8.onDestroyView():在移除与片段关联的视图层次结构时调用。
9.onDestory():销毁Fragment时调用。
10.onDetach():在取消片段与 Activity 的关联时调用。
Fragment虽然有自己的生命周期,但也和Activity的生命周期相关联。
举个例子说明:在Activity的onCreate()中直接add一个Fragment,其log日志如下:
可以发现:
1.Fragment的onAttach()->onCreate()->onCreateView()->onViewCreated()->onStart()都是在Activity的onStart()开始后执行的。
2.在Activity的onResume()执行完后,才开始执行Fragment的onResume()方法。
当通过物理返回键关闭当前Activity时,其log日志如下:
可以发现:
1.Activity的onPause()、onStop()与Fragment的onPause()、onStop()都是间隔执行。
2.Activity开始执行onDestroy()后,Fragment会先执行完剩余的生命周期,即:onDestroyView()->onDestroy()->onDetach(),此时Fragment已经完全从依赖的Activity脱离,Activity最后被销毁。
DialogFragment简介
DialogFragment也是在3.0时引入的,是一种特殊的Fragment,用于在Activity上展示一个模态的对话框。在DialogFragment之前,一般通过Dialog来构建对话框,但官方已经不推荐这种方法了,因为不能有效的管理Dialog的生命周期。而DialogFragment的好处就在于对Dialog生命周期的管理,特别是在旋转屏幕、按下后退键等让Activity重建或者销毁的场景。而且DialogFragment可以把Dialog作为内嵌组件进行重用,类似Fragment。
onCreateView
或者
onCreateDialog
方法。
onCreateView
方法使用定义的布局xml文件来展示Dialog,而
onCreateDialog
则是使用AlertDialog或者自定义Dialog来展示。
使用onCreateView方法创建Dialog
简单的定义一个xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp"/>
<Button
android:id="@+id/show"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Show"
android:textSize="16sp"/>
</LinearLayout>
创建DialogFragment类:
public class MyDialogFragment extends DialogFragment {
private static final String TAG = MyDialogFragment.class.getSimpleName();
int mNum;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mNum = getArguments().getInt("num");
int style = DialogFragment.STYLE_NORMAL, theme = 0;
switch ((mNum-1)%6) { // 使用不同的style
case 1: style = DialogFragment.STYLE_NO_TITLE; break;
case 2: style = DialogFragment.STYLE_NO_FRAME; break;
case 3: style = DialogFragment.STYLE_NO_INPUT; break;
case 4: style = DialogFragment.STYLE_NORMAL; break;
case 5: style = DialogFragment.STYLE_NORMAL; break;
case 6: style = DialogFragment.STYLE_NO_TITLE; break;
case 7: style = DialogFragment.STYLE_NO_FRAME; break;
case 8: style = DialogFragment.STYLE_NORMAL; break;
switch ((mNum-1)%6) { // 使用不同的主题
case 4: theme = android.R.style.Theme_Holo; break;
case 5: theme = android.R.style.Theme_Holo_Light_Dialog; break;
case 6: theme = android.R.style.Theme_Holo_Light; break;
case 7: theme = android.R.style.Theme_Holo_Light_Panel; break;
case 8: theme = android.R.style.Theme_Holo_Light; break;
setStyle(style, theme);
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_dialog, container, false);
TextView tv = v.findViewById(R.id.text);
tv.setText("Dialog #" + mNum + ": using style "
+ getNameForNum(mNum));
Button button = v.findViewById(R.id.show);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
((MainActivity)getActivity()).showDialog();
return v;
在Activity中使用:
public void showDialog() {
mStackLevel++;
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment prev = getSupportFragmentManager().findFragmentByTag("dialog");
if (prev != null) {
ft.remove(prev);
ft.addToBackStack(null); // 加入到回退栈
DialogFragment newFragment = MyDialogFragment.newInstance(mStackLevel);
newFragment.show(ft, "dialog"); // 调用show方法
效果如图:
通过show按钮可以继续展示新的Dialog,因为将旧Dialog加入到了回退栈中,所以在按返回键时,会显示前一个Dialog。
使用onCreateDialog方法创建Dialog
为方便起见,这里直接使用系统的AlertDialog了。
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
int title = getArguments().getInt("title");
return new AlertDialog.Builder(getActivity())
.setIcon(R.mipmap.ic_launcher)
.setTitle(title)
.setPositiveButton("确认", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
((MainActivity)getActivity()).doPositiveClick();
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
((MainActivity)getActivity()).doNegativeClick();
.create();
在Activity中调用:
public void showAlertDialog() {
DialogFragment alertDialog = MyAlertDialogFragment.newInstance(R.string.app_name);
alertDialog.show(getSupportFragmentManager(), "alert");
效果如图:
可以正常的展示AlertDialog。
将Dialog作为内嵌组件
如果希望通过DialogFragment实现一种Dialog,它既可以用对话框的样式展示,也可以内嵌在Activity的内容中,则只能通过 onCreateView
方法实现,举例:
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_simple_dialog, container, false);
TextView tv = view.findViewById(R.id.text);
tv.setText("this is an instance of MySimpleDialogFragment");
return view;
如果希望它以对话框样式展示,则:
public void showSimpleDialogAsDialog(View view) {
DialogFragment simple = MySimpleDialogFragment.newInstance();
simple.show(getSupportFragmentManager(), "dialog");
如果希望它内嵌在Activity中,则:
public void showSimpleDialogAsViewHierarchy(View view) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
DialogFragment simple = MySimpleDialogFragment.newInstance();
ft.add(R.id.embedded, simple); // R.id.embedded是容器,这里是FrameLayout
ft.commit();
通过DialogFragment创建的Dialog不会因为屏幕的旋转而关闭,其输入在上面的内容也不会被清空,这里就不展示了。
DialogFragment的源码浅析
打开DialogFragment的源码,发现其内容并不多,可以看到它保存了 Dialog
实例:
所以DialogFragment能展示对话框。show
方法:
public void show(FragmentManager manager, String tag) {
this.mDismissed = false;
this.mShownByMe = true;
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag); // 调用add
ft.commit(); // commit是异步的
public int show(FragmentTransaction transaction, String tag) {
this.mDismissed = false;
this.mShownByMe = true;
transaction.add(this, tag); // 调用add
this.mViewDestroyed = false;
this.mBackStackId = transaction.commit(); // commit是异步的
return this.mBackStackId;
public void showNow(FragmentManager manager, String tag) {
this.mDismissed = false;
this.mShownByMe = true;
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commitNow(); // commitNow是同步的
都是通过 FragmentTransaction
来添加DialogFragment,且提供了同步和异步的方法。onSaveInstanceState
方法:
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
if (this.mDialog != null) {
Bundle dialogState = this.mDialog.onSaveInstanceState();
if (dialogState != null) {
outState.putBundle("android:savedDialogState", dialogState);
if (this.mStyle != 0) {
outState.putInt("android:style", this.mStyle);
if (this.mTheme != 0) {
outState.putInt("android:theme", this.mTheme);
if (!this.mCancelable) {
outState.putBoolean("android:cancelable", this.mCancelable);
if (!this.mShowsDialog) {
outState.putBoolean("android:showsDialog", this.mShowsDialog);
if (this.mBackStackId != -1) {
outState.putInt("android:backStackId", this.mBackStackId);
保存了Dialog的一系列状态值。dismissInternal
:
void dismissInternal(boolean allowStateLoss) {
if (!this.mDismissed) {
this.mDismissed = true;
this.mShownByMe = false;
if (this.mDialog != null) {
this.mDialog.dismiss(); // 对话框消失
this.mViewDestroyed = true;
if (this.mBackStackId >= 0) { // 回退栈的处理
this.getFragmentManager().popBackStack(this.mBackStackId, 1);
this.mBackStackId = -1;
} else {
FragmentTransaction ft = this.getFragmentManager().beginTransaction();
ft.remove(this);
if (allowStateLoss) {
ft.commitAllowingStateLoss();
} else {
ft.commit();
最后,可以在各个生命周期的方法中看到对保存的Dialog也做了处理,如:
public void onStop() {
super.onStop();
if (this.mDialog != null) {
this.mDialog.hide(); // 对话框隐藏
public void onDestroyView() {
super.onDestroyView();
if (this.mDialog != null) {
this.mViewDestroyed = true;
this.mDialog.dismiss(); // 对话框销毁
this.mDialog = null;
嗯~本文的内容就这么多https://github.com/zjxstar/AndroidSamples/tree/master/DialogSample
1.官方文档 https://developer.android.com/guide/components/fragments#Lifecycle
2.Android 官方推荐 : DialogFragment 创建对话框 https://blog.csdn.net/lmj623565791/article/details/37815413
3.《Android Fragment 非常详细的一篇》https://www.jianshu.com/p/11c8ced79193
--END--
相信看这篇文章的人都应该知道android中的Dialog了吧,如果对于Dialog还不是很了解可以看我之前的一篇详解文章:
Dialog详解:http://www.cnblogs.com/tianzhijiexian/p/3867731.html
随着Fragment这个类的引入,Google官方推荐大家使用DialogFragment来代替传统的Dialog,那么是不是说我们之前学习的Dialog知识都没有用处了呢?非也,新的fragment是来方便大家更好的管理和重用Dialog,之前的知识其..
项目里一直使用dialog,最近才发现谷歌早就推出了DialogFragment,由于平常写项目需求基本也都是继承dialog重写,发现使用DialogFragment更加方便,也是谷歌推荐替换的,所以来学习一下DialogFragment的用法。
DialogFragment的基本使用
使用一个DialogFragment一般我们需要重新写一个类来...
1、
DialogFragment在锁屏、界面处于休眠等状态下调用show和dismiss会引发IllegalStateException异常。
2、
DialogFragment在show()和dismiss()时判断是否弹出问题
3、和
Fragment一样的o
nAttach(Activity activity)过时引用o
nAttach(Context context)高低版本不兼容问题
DialogFragment的实例newInstance()已经在上一次学习笔记中实现。我们创建dialog的UI,可以通过重写DialogFragment的两个函数当中的一个来实现,这两个函数是onCreateView()和onCreateDialog(),前者返回view,后者返回dialog,如同通过AlertDialog.Builder构造一样。
重写onCreateView()
DialogFragment 是android3.0以后推出的,用来替代Dialog,它其实就是一个fragment,具有fragment的所有生命周期,比Dialog更好管理。
简单的封装一下:
public abstract class BaseDialogFragment extends DialogFragment {
protected Dialog dialog = null...
dialogFragment投入使用有几个月了,今天因为功能的原因需要设置dismiss监听,在onCreateDialog中给dialog设置的监听,结果运行时监听不到?
经过打log发现dismiss的时候没有走dismiss和dialog的DialogInterface.OnDismissListener,而是直接走了onDestroy?
@Override
public void ...