How to use DialogFragments instead of AlertDialogs in Android

In this post we will be discussing the use of DialogFragments in Android. We will see how to migrate away from Dialogs.

Google recommends DialogFragment to be used instead of the old standard dialog utilities. DialogFragment is nothing but a dialog inflated inside a fragment. Since it’s a fragment, DialogFragment follows its own lifecycle like any other fragment. This will save you from the famous IllegalStateException due to destroyed activity causing leaked windows.

There are two ways to create a dialog using DialogFragment.

  1. Similar to any fragment a dialog can be inflated in onCreateView method of the fragment by inflating a custom layout.
  2. onCreateDialog method can be used to create AlertDialog using the builder class.

We will see now how to create dialogs both via onCreateView and onCreateDialog. Let’s create an activity that will host two buttons to create each type of DialogFragment.

 

 

The xml layout of the activity is defined in activity_dialog.xml as follows:

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".DialogActivity">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </com.google.android.material.appbar.AppBarLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginStart="8dp"
        android:layout_marginEnd="8dp"
        android:gravity="center"
        android:orientation="vertical">

        <Button
            android:id="@+id/button3"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="btnOnCreateView"
            android:text="onCreateView" />

        <Button
            android:id="@+id/button4"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="btnOnCreateDialog"
            android:text="onCreateDialog" />
    </LinearLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

I have defined two buttons. Each button will create a different kind of DialogFragment as explained above.

The activity code is defined in DialogActivity.java

package com.codeexa.dialogfragment;

import android.os.Bundle;

import com.codeexa.dialogfragment.ui.dialog.CustomAlertDialogFragment;
import com.codeexa.dialogfragment.ui.dialog.CustomDialogFragment;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;

import android.view.View;

public class DialogActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_dialog);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

    }

    public void btnOnCreateView(View view) {
        CustomDialogFragment customDialogFragment = CustomDialogFragment.newInstance("Message", true);
        customDialogFragment.show(getSupportFragmentManager(), "CustomDialogFragment");
    }

    public void btnOnCreateDialog(View view) {
        CustomAlertDialogFragment customDialogFragment = CustomAlertDialogFragment.newInstance();
        customDialogFragment.show(getSupportFragmentManager(), "CustomAlertDialogFragment");
    }
}

In the activity I have create two methods that will create DialogFragment using onCreateView and onDialogCreated method respectively.

onCreateView

CustomDialogFragment uses onCreateView to create Dialog. There is also an option to display Dialog in fullscreen or as an alert dialog.

package com.codeexa.dialogfragment.ui.dialog;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;

import com.codeexa.dialogfragment.R;
import com.google.android.material.textfield.TextInputEditText;

public class CustomDialogFragment extends DialogFragment implements View.OnClickListener {

    private String mName;
    private TextInputEditText etUserEmail, etUserPassword;

    public static CustomDialogFragment newInstance(String name, boolean isFullScreen){
        Bundle b = new Bundle();
        b.putString("key", name);
        CustomDialogFragment fragment = new CustomDialogFragment();
        if(isFullScreen)
            fragment.setStyle(DialogFragment.STYLE_NORMAL, R.style.Theme_AppCompat_Light_NoActionBar);
        else
            fragment.setStyle(DialogFragment.STYLE_NORMAL, R.style.Theme_AppCompat_Light_Dialog_Alert);
        fragment.setArguments(b);
        return fragment;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mName = getArguments().getString("isFullScreen");
    }

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

        etUserEmail = v.findViewById(R.id.userMail);
        etUserPassword = v.findViewById(R.id.userPassword);
        Button btnRegiser = v.findViewById(R.id.btnRegister);
        btnRegiser.setOnClickListener(this);
        return v;
    }

    private void btnOnRegister(){

    }

    @Override
    public void onClick(View v) {
        if(v.getId() == R.id.btnRegister)
            btnOnRegister();
    }
}

 

If the use case is to display dialog as full screen then we need to set the style of the dialog before showing it to the user.

For full screen display set style of dialog fragment as shown below in the code snippet.

fragment.setStyle(DialogFragment.STYLE_NORMAL, R.style.Theme_AppCompat_Light_NoActionBar);

For alert dialog set style as below.

fragment.setStyle(DialogFragment.STYLE_NORMAL, R.style.Theme_AppCompat_Light_Dialog_Alert);

onDialogCreated

onDialogCreated method is used when you just need to display the standard alert dialog without any need to create custom view.

package com.codeexa.dialogfragment.ui.dialog;

import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;

import com.codeexa.dialogfragment.R;
import com.google.android.material.textfield.TextInputEditText;

public class CustomAlertDialogFragment extends DialogFragment {

    public static CustomAlertDialogFragment newInstance(){
        return new CustomAlertDialogFragment();
    }


    @NonNull
    @Override
    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setTitle("Title");
        builder.setMessage("This is an example of AlertDialog inside a fragment.");

        builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dismiss();
            }
        });

        builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
            }
        });

        return builder.create();
    }

}

 

 

Leave a Reply