Furudateのブログ

プログラミングやネットワーク系の知識・技術がメインのブログ。技術メモ帳的な感じになるかと。岩手から発信していきます。

【Android】キャンセルボタン対応のProgressDialog

こんにちは。

前回のエントリーでDialogFragmentについて触れました。

この記事の中でProgressDialogを実装していますが、今回はこのProgressDialogにキャンセルボタンを付けたいと思います。

それでは早速コードを書きます。

なお、インスタンス生成時の引数でリスナーやタイトル等を設定するのと、これらをメンバ変数にし、Activity側でBundleにセットする方法の二つがあります(こちらのサイトでは、こちらの方法で実装しています)。 どちらがいいのかは分かりませんが、まぁ趣味ですかね。笑

今回は、インスタンス生成次の引数で設定する方法で書きたいと思います。 Activity側でBundleにセットする方法については、上記のサイト様にも書いてあるので、こちらを参考にしてください。

では、早速実装していきます。

まずはProgressDialogのDialogFragmentです。

public class MyProgressDialogFragment extends DialogFragment{
    private static ProgressDialog progressDialog = null;
    private CancelListener listener; // リスナー用の変数です
    
    // インスタンス生成時にシリアライズ(リスナーを追加)
    public static MyProgressDialogFragment newInstance(String title, String message, Boolean cancel, Serializable Cancel_Listener){
        MyProgressDialogFragment instance = new MyProgressDialogFragment();
        
        // ダイアログにパラメータを渡す
        Bundle arguments = new Bundle();
        arguments.putString("title", title);
        arguments.putString("message", message);
        arguments.putBoolean("cancel", cancel);
        if (cancel) // キャンセルの場合
            arguments.putSerializable("Cancel_Listener", Cancel_Listener);
        
        instance.setArguments(arguments);
        
        return instance;
    }
    
    // キャンセルリスナ
    public interface CancelListener extends Serializable{
        public void canceled(DialogInterface _interface);
    }
    
    // ProgressDialog作成
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState){
        if (progressDialog != null)
            return progressDialog;
        
        // パラメータを取得
        String title = getArguments().getString("title");
        String message = getArguments().getString("message");
        Boolean cancel = getArguments().getBoolean("cancel", false);
        // リスナーを設定
        listener = (CancelListener)getArguments().getSerializable("Cancel_Listener");
        
        progressDialog = new ProgressDialog(getActivity());
        progressDialog.setTitle(title);
        progressDialog.setMessage(message);
        progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); // プログレスダイアログのスタイルを円スタイルに設定
        // プログレスダイアログのキャンセルが可能かどうかを設定(バックボタンでダイアログをキャンセルできないようにする)
        setCancelable(cancel);
        
        if (cancel){ // キャンセルボタンありの場合はボタンを追加します。
            progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "キャンセル", new DialogInterface.OnClickListener(){
                @Override
                public void onClick(DialogInterface dialog, int which){
                   listener.canceled(dialog);
                }
             });
        }   
        
        return progressDialog;
    }
    
    // progressDialog取得
    @Override
    public Dialog getDialog(){
        return progressDialog;
    }
    
    // ProgressDialog破棄
    @Override
    public void onDestroy(){
        super.onDestroy();
        progressDialog = null;
    }
    
    // キャンセルのときに、リスナーに通知します。
    @Override
    public void onCancel(DialogInterface dialog){
       if (getArguments().getBoolean("cancel", false)){
          listener.canceled(dialog);
       }
    }
}

こんな感じです。 キャンセルボタンなしのときとの大きな違いは、リスナーを設定していることです。 これでActivity側にキャンセルボタンが押されたことを通知します。

次にActivity側です。 Activityでは、ボタンを押したらDialogを表示するようにします。

public class MainActivity extends Activity implements OnClickListener{

    MyProgressDialogFragment progressDialog = null;    // ロード中画面のプログレスダイアログ作成
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button btn = (Button)findViewById(R.id.button1);
        btn.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        // キャンセルリスナーの実装
        @SuppressWarnings("serial")
        Serializable Cancel_Listener = new MyProgressDialogFragment.CancelListener() {
            @Override
            public void canceled(DialogInterface _interface) {
                Toast.makeText(MainActivity.this, "キャンセルされました", Toast.LENGTH_SHORT).show();
            }
        };
        progressDialog = MyProgressDialogFragment.newInstance("ネットワークに接続中です", "しばらくお待ちください", true, Cancel_Listener);
        progressDialog.show(getFragmentManager(), "progress");
        
        if (progressDialog != null){ // Dialogが表示されている場合(なぜかisVisibleが使えなかったのでこっちで処理)
            Toast.makeText(this, "表示中", Toast.LENGTH_SHORT).show();
        }
    }
}

こんな感じです。

特に難しいことはしていませんが、キャンセルリスナーの実装のところだけ注意してください。

今回は無名関数でやっていますが、独自のリスナーを定義してやるのもありだと思います(前回の記事のAlertDialogではそのようにしています)。

また、DialogFragment#isVisible()でダイアログが表示中かどうかを取得できると思ったのですが、表示していてもしていなくてもFalseになってしまうので、null判定にしました。 今のところこれで出来ているので良いですが、なんで出来ないんですかね・・・

とりあえずこんな感じでキャンセルボタンに対応することが出来ました!

今回は以上です。 それでは。

2014年1月16日追記

ProgressDialogが表示中かどうかはgetShowsDialog()で取得できました。

参考にさせていただいたサイト

画面回転、キャンセル対応のProgress DialogFragment