LoginSignup
4
5

More than 5 years have passed since last update.

Dialogの実装を統一化するプラクティス

Posted at

概要

AndroidでDialogを実装するとき、Activityにinner classとしてDialogFragmentを実装する方法をよく使っていましたが、Activityのステップ数が多くなってしまうのと、Dialogがどこにあるのかわかりづらいと感じていたので、Dialogの実装を統一化するプラクティスを考えました。

詳細

Activity内にDialogを実装するのではなくDialog表示のためのFactoryを使う。
DialogのshowもActivityではなく共通クラスに任せる。
ソースコードはGitHubより取得お願いします。
https://github.com/ken-maki/k_commons.dialog

構成は以下。

com.android.k.commons.dialog
┣lib
┃┣BaseDialogFactory
┃┃ DialogのBaseFactoryクラス、Dialog生成に関する共通的な実装はここに書く。
┃┣AlertDialogFactory
┃┃ AlertDialog実装用の親Factoryクラス、AlertDialogを新規作成するときはこのクラスを継承する。
┃┣DialogGenerator
┃┃ Dialog表示を担うクラス、Factoryを渡してあげてDialogさせる。
┃┃ Dialog生成時の制御(例えば、重複表示を抑止)の実装はここに書く。
┃┗CommonAlertDialog
┃  AlertDialog本体。引数に取ったFactoryからBuilderを取得しonCreateDialogのBuilderとして使う。
┣mydialog
┃┣MySampleFooDialogFactory
┃┃ サンプル用DialogFactory、ボタンのクリックイベントをFactory内で実装するパターン。
┃┗MySampleBarDialogFactory
┃  サンプル用DialogFactory、ボタンのクリックイベントをFactoryに設定されたリスナで実装するパターン。
┗MainActivity
   ダイアログ表示のサンプルActivity。
   MySampleBarDialogFactory表示のときに自前でOnClickListenerを実装する。

ソースの解説

ライブラリ部分

AlertDialogFactory.java
abstract class BaseDialogFactory implements Serializable {

    DialogInterface.OnCancelListener mOnCancelListener;
    DialogInterface.OnDismissListener mOnDismissListener;

    /**
     * Activity to display Dialog.
     */
    private Activity mActivity;

    /**
     * Constructor.
     *
     * @param activity create dialog for activity.
     */
    BaseDialogFactory(Activity activity) {
        if (activity == null) throw new IllegalArgumentException("activity is null.");
        mActivity = activity;
    }

    /**
     * get Activity.
     *
     * @return Activity
     */
    protected Activity getActivity() {
        return mActivity;
    }

    /**
     * get Dialog Tag.
     *
     * @return Dialog Tag
     */
    protected String getTag() {
        return this.getClass().getSimpleName();
    }

    /**
     * set OnCancelListener.
     * @param listener action listener
     */
    public void setOnCancelListener(DialogInterface.OnCancelListener listener) {
        mOnCancelListener = listener;
    }

    /**
     * set OnDismissListener.
     * @param listener action listener
     */
    public void setOnDismissListener(DialogInterface.OnDismissListener listener) {
        mOnDismissListener = listener;
    }
}

DialogFactoryの親クラス、共通的な処理を実装しています。

AlertDialogFactory.java
public abstract class AlertDialogFactory extends BaseDialogFactory {

    protected DialogInterface.OnClickListener mPositiveClickListener;
    protected DialogInterface.OnClickListener mNegativeClickListener;

    /**
     * Constructor.
     *
     * @param activity create dialog for activity.
     */
    public AlertDialogFactory(Activity activity) {
        super(activity);
    }

    /**
     * create AlertDialog.Builder.
     *
     * @return can be Show AlertDialog.Builder
     */
    public abstract AlertDialog.Builder build();

    /**
     * set OnClickListener for PositiveButton click.
     * @param listener action listener
     */
    public void setPositiveOnClickListener(DialogInterface.OnClickListener listener) {
        mPositiveClickListener = listener;
    }

    /**
     * set OnClickListener for NegativeButton click.
     * @param listener action listener
     */
    public void setNegativeClickListener(DialogInterface.OnClickListener listener) {
        mNegativeClickListener = listener;
    }
}

AlertDialogのFactoryクラス。親build()メソッドがこのクラスの主役です。
AlertDialogFactoryを継承したクラスは、build()メソッド内に表示したい情報の
AlertDialog.Builderを生成、返却する実装を作成するだけでOK。
もしAlertDialog以外のDialogを使いたいときはAlertDialogFactoryのような感じで
親Factoryを作成する。(SingleChoiceDialogFactoryとかDatePickerDialogFactoryとか)

CommonAlertDialog.java
public class CommonAlertDialog extends DialogFragment {
    private static final String ARG_KEY_FACTORY = "f";

    AlertDialogFactory mFactory;

    public static CommonAlertDialog newInstance(AlertDialogFactory factory) {
        Bundle bundle = new Bundle();
        bundle.putSerializable(ARG_KEY_FACTORY, factory);

        CommonAlertDialog dialog = new CommonAlertDialog();
        dialog.setArguments(bundle);
        return dialog;
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        mFactory = (AlertDialogFactory)
                getArguments().getSerializable(ARG_KEY_FACTORY);
        if (mFactory == null) throw new IllegalArgumentException("factory is null.");

        AlertDialog.Builder builder = mFactory.build();
        if (builder == null) throw new IllegalStateException("AlertDialog.Builder is null.");
        return builder.create();
    }

    @Override
    public void onCancel(DialogInterface dialog) {
        super.onCancel(dialog);
        if (mFactory.mOnCancelListener != null) {
            mFactory.mOnCancelListener.onCancel(dialog);
        }
    }

    @Override
    public void onDismiss(DialogInterface dialog) {
        super.onDismiss(dialog);
        if (mFactory.mOnDismissListener != null) {
            mFactory.mOnDismissListener.onDismiss(dialog);
        }
    }

    /**
     * return AlertDialogFactory.
     * @return AlertDialogFactory
     */
    public AlertDialogFactory getFactory() {
        return mFactory;
    }
}

Dialog本体。
やってることは大まかに以下の2つ。
・引数からFactoryをとってきて、createする。
・DialogInterfaceのイベントが設定されてたら実行する。

個々の実装部分

MySampleFooDialogFactory.java
public class MySampleFooDialogFactory extends AlertDialogFactory {

    public MySampleFooDialogFactory(Activity activity) {
        super(activity);
    }

    @Override
    public AlertDialog.Builder build() {
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

        builder.setTitle("Foo Dialog");
        builder.setMessage("This Foo Dialog. please Button Click.");
        builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Toast.makeText(getActivity(), "Ok clicked.(listener setting from factory)", Toast.LENGTH_SHORT).show();
                dialog.dismiss();
            }
        });
        builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Toast.makeText(getActivity(), "Cancel clicked.(listener setting from factory)", Toast.LENGTH_SHORT).show();
                dialog.dismiss();
            }
        });

        builder.setCancelable(false);
        return builder;
    }
}

AlertDialogFactoryを継承してbuild()を実装するだけ。
サンプルは簡素な実装ですが、カスタムレイアウトなどを使う複雑なDialogのときも
処理はbuild()に実装。
こうすることでDialog作成時はDialogの中身を作ることだけに集中できる。

メリット

-Dialog実装する人はAlertDialog.Builderを生成するコードの実装だけに集中できる。
 共通処理はDialogGeneratorなりAlertDialogFactoryなりCommonAlertDialogなりに
 実装することで、AlertDialog全体が統一された動作になる。
-Activity内に直接Dialogの実装とDialogをshowする実装が無くなる
 Activityと疎結合になるのでinner classでの実装に比べDialog側の変更がしやすくなるはず。

終わりに

Qiita初投稿でしたが、こんな感じの記事でいいのかなぁ。
試行錯誤で今後も記事投稿していきますので、生暖かい目で見守ってくださると幸いです。

ソースコード
https://github.com/ken-maki/k_commons.dialog

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5