【教えてください】AlertDialogについて

2,132 views
Skip to first unread message

micco

unread,
Aug 20, 2010, 11:34:30 AM8/20/10
to 日本Androidの会
こんばんは。
miccoです。

また初歩的なことで立ち止まってしまいました。
ボタンを押下すると、OK/キャンセルを選択するAlertDialogを表示させて、OKボタンをクリックした場合には、
あるデータ消去メソッドを実行するようなプログラムを書いています。
データ消去に一定時間を要するため、プログレスダイアログを表示したいと考えて、以下のように実装してみ
ましたが、プログレスダイアログは表示されません。
AlertDialogが表示された状態から抜けてないからだと思いますが、この解決方法が分からず困っています。
どなたかご教授ください。
よろしくお願いします。

public void onClick(View view)
{
AlertDialog.Builder ad = new AlertDialog.Builder(this);
ad.setTitle("確認");
ad.setMessage(全データを消去します");
ad.setPositiveButton("キャンセル",new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface di,int which_button)
{
//何もしない
}
});
ad.setNegativeButton("消去",new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface di,int which_button)
{
deleteData();
}
});
ad.create();
ad.show();
}

private void deleteData()
{
//プログレスダイアログ生成
ProgressDialog pDialog = new ProgressDialog(this);
pDialog.setTitle("データ消去中");
pDialog.setMessage("しばらくお待ち下さい");
pDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
pDialog.show();
//データ消去処理
・・(略)・・・・・・・・・・・・・・
//プログレスダイアログ消去
pDialog.dimiss();
}

重村浩二

unread,
Aug 20, 2010, 12:00:45 PM8/20/10
to android-g...@googlegroups.com
miccoさん

重村です。
こんばんは。

下記件ですが、ダイアログの終了メソッドdismiss()をAlertDialogにも
実行してやればOKだと思いますよ。

タイミング的にほんとに大丈夫なのか・・・
という検証までは完了していないのですが、
以下のコードでEmulatorでは正常動作しておりましたので、
お試しください。

AlertDialog.Builder ad = new AlertDialog.Builder((Activity)v.getContext());
ad.setTitle("確認");
ad.setMessage("全データを消去します");
ad.setPositiveButton("キャンセル",new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface di,int which_button)
{
//何もしない
}
});
ad.setNegativeButton("消去",new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface di,int which_button)
{
// ダイアログの終了
di.dismiss();
// データ削除
deleteData();
}
});
ad.create();
ad.show();
private void deleteData()
{
ProgressDialog.show(DialogActivity.this, "", "待ってます。。。", false, true);
}

以上、よろしくお願い致します。

2010年8月21日0:34 micco <gou...@gmail.com>:

--
このメールは Google グループのグループ「日本Androidの会」の登録者に送られています。
このグループに投稿するには、android-g...@googlegroups.com にメールを送信してください。
このグループから退会するには、android-group-j...@googlegroups.com にメールを送信してください。
詳細については、http://groups.google.com/group/android-group-japan?hl=ja からこのグループにアクセスしてください。




--
日本Androidの会
幹事 中国支部長
重村 浩二(SHIGEMURA Koji)
tel: 090-7546-5107
mail: k-shi...@android-group.jp

micco

unread,
Aug 20, 2010, 12:53:15 PM8/20/10
to 日本Androidの会
重村さん

こんばんは。
miccoです。

早速のコメントありがとうございます!
投稿前に試したことを書いていなかったのですが、AlertDialogもdismiss()で閉じれば
良いと思いまして、以下のようにdismiss()の実行を追記して試しております。
これでIS01とエミュレーター双方でテストしましたが、やはり表示されませんでした。
OK押下後、しばらくAlertDialogが表示されて固まったままとなり、裏でデータ消去メ
ソッドが作業しています。
AlertDialogが閉じられると同時に消去メソッドから抜けます。
何か気をつけるべき点がありますでしょうか?



ad.setNegativeButton("消去",new
DialogInterface.OnClickListener()
{
public void onClick(DialogInterface di,int
which_button)
{
di.dismiss();
deleteData();
}
});
> > このグループから退会するには、android-group-j...@googlegroups.com<android-gro-up-japan%2Bunsu...@googlegroups.com>にメールを送信してください。
> > 詳細については、http://groups.google.com/group/android-group-japan?hl=jaからこのグループにアクセスしてください。
>
> --
> 日本Androidの会
> 幹事 中国支部長
> 重村 浩二(SHIGEMURA Koji)
> tel: 090-7546-5107
> mail: k-shigem...@android-group.jp- 引用テキストを表示しない -
>
> - 引用テキストを表示 -

夜子まま

unread,
Aug 20, 2010, 1:04:07 PM8/20/10
to android-g...@googlegroups.com
夜子ままです

重村さんにかわって、、

こういう重い処理をイベント内でする場合はAsyncTaskを使うといいです。
とはいってもプログレスバーを出す場合はちょっと工夫しないといけないので、
次のようなクラスを作ってやればいいとおもいます。

下のクラスの使い方は

BackgroundTask  task = new BackgroundTask(this, ”Loading...”){
 @Override
 protected Long doInBackground(String... params) {
     deleteData();
   }
}};
task.execute((String)null);

こんな感じ、タスク内でActivityへの変更処理をする場合は
Handlerをつかってください。


public abstract class BackgroundTask extends AsyncTask<String, Integer, Long> {
protected Context context= null;
protected ProgressDialog dialog = null;
protected String msg;
protected Handler handler;

public BackgroundTask(Context context, String msg) {
this.context= context;
this.msg = msg;
}
@Override
protected void onPreExecute() {
// プログレスバー設定
dialog = new ProgressDialog(context);
dialog.setIndeterminate(true);
dialog.setMessage(msg);
dialog.show();

// Handlerを設定
handler = new Handler();
}


@Override
protected void onProgressUpdate(Integer... progress) {

}
@Override  
protected void onPostExecute(Long result) {
try{
dialog.dismiss();
}
catch(Exception e){}
}
}

#このクラス、ちょっとMailに乗せるには無駄なコードがおおかったのでいくつかはしょってます、
そのせいでうごかないかも、そのときはまたメールください。

2010年8月21日1:53 micco <gou...@gmail.com>:

重村浩二

unread,
Aug 20, 2010, 1:05:05 PM8/20/10
to android-g...@googlegroups.com
miccoさん

重村です。

deleteDetail()内で消す処理とプログレスダイアログを表示する処理を
同時にしているのがまずいかと思います。
上記の処理だと、ProgressDialogはスタックに積まれて、画面表示しようとしているのですが、
シングルスレッドの状態となっていますので、
onClick()処理終了後のAlertDialogの終了処理に行く前に削除処理を行い、その後に書かれたdismiss()で
スタックに積まれたProgressDialogが終了されるので、
結果的にProgressDialogが見えないのだと推察されます。
シーケンスで表すと以下のような感じですね。

onClick()
  deleteDetail()
    ...データ削除処理... ←この処理を待つ間、AlertDialogの終了処理が走れない
    dismiss()      ←☆ProgressDialogが終了されてしまう

AlertDialogを閉じ、削除処理中のProgressDialogを出すには、マルチスレッド化を行ない、
上記の処理の場合、削除処理と同時にonClick()も終了し、AlertDialogが終了するようにすれば、
ProgressDialogが出るようになると思います。

それには、AsyncTaskまたはHandlerで行えばよいのではないかと。

ではでは。

2010年8月21日1:53 micco <gou...@gmail.com>:
このグループから退会するには、android-group-j...@googlegroups.com にメールを送信してください。
詳細については、http://groups.google.com/group/android-group-japan?hl=ja からこのグループにアクセスしてください。


--
日本Androidの会
幹事 中国支部長
重村 浩二(SHIGEMURA Koji)
tel: 090-7546-5107

micco

unread,
Aug 20, 2010, 10:00:00 PM8/20/10
to 日本Androidの会
こんにちは。
miccoです。

>重村さん
解説ありがとうございます。
ダメな理由がよく分かりましたw

>夜子ままさん
具体的な記述方法のご教授ありがとうございます!
なかなか手の込んだことをやらないといけないのですね。。。
今の私のレベルですと、もっと理解を深めないと実装が難しそうです^^;

またご相談させて頂くかもしれませんが、よろしくお願いいたします。
> > <android-gro-up-japan%2Bunsu...@googlegroups.com<android-gro-up-japan%2-52Buns...@googlegroups.com>
> > >にメールを送信してください。
> > > > 詳細については、http://groups.google.com/group/android-group-japan?hl=ja
> > からこのグループにアクセスしてください。
>
> > > --
> > > 日本Androidの会
> > > 幹事 中国支部長
> > > 重村 浩二(SHIGEMURA Koji)
> > > tel: 090-7546-5107
> > > mail: k-shigem...@android-group.jp- 引用テキストを表示しない -
>
> > > - 引用テキストを表示 -
>
> > --
> > このメールは Google グループのグループ「日本Androidの会」の登録者に送られています。
> > このグループに投稿するには、android-g...@googlegroups.com にメールを送信してください。

mosaki4

unread,
Aug 21, 2010, 1:04:56 AM8/21/10
to android-g...@googlegroups.com
大崎といいます、

夜子ままさんのソースをベースに動作するサンプルソースを記述します
夜子ままさんと一部違う意見としては Handler は使わない方法を提案します

理由はAsyncTaskを使えば別スレッドでのバックグランド処理とUIスレッドへの
反映を内部的に行ってくれるのでHandlerを使わないで画面を更新しても
例外が発生しないようになっているからです。

1点だけ注意点としては、
doInBackgroundではUIスレッドへの操作を行ってはいけません
進捗の表示等が必要な場合はonProgressUpdateでUIスレッドへの操作を行うことで正しく動作します。


public class BackgroundTask2 extends AsyncTask<Void, Integer, Boolean> {
protected Context context= null;
protected ProgressDialog dialog = null;

public BackgroundTask2(Context context) {
this.context= context;
}
@Override
protected void onPreExecute() {
// 処理実行前を記述するメソッド
// プログレスバー設定
dialog = new ProgressDialog(context);
dialog.setIndeterminate(false);
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setTitle("データ消去中");
dialog.setMessage("しばらくお待ち下さい");
dialog.show();
}

@Override
protected Boolean doInBackground(Void... params) {
// 処理実行中を記述するメソッド
// ここでは実際の処理の変わりにダミーでSleepを入れている
for(int i=0;i<=100;i++){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 進捗を設定
publishProgress(i);
}
return true;
}

@Override
protected void onProgressUpdate(Integer... progress) {
// 進捗を記述するメソッド
// プログレスバーの進捗を設定
dialog.setProgress(progress[0]);
}
@Override  
protected void onPostExecute(Boolean result) {
// 処理実行後を記述するメソッド
// プログレスバーを閉じる
try{
dialog.dismiss();
}
catch(Exception e){}
}

}


2010年8月21日11:00 micco <gou...@gmail.com>:
このグループから退会するには、android-group-j...@googlegroups.com にメールを送信してください。
詳細については、http://groups.google.com/group/android-group-japan?hl=ja からこのグループにアクセスしてください。


micco

unread,
Aug 22, 2010, 11:02:53 AM8/22/10
to 日本Androidの会
こんばんは。
miccoです。

>大崎さん
追加コメントありがとうございます!
参考にさせていただきます。

>みなさま
AlertDialogとProgressDialogのバッティングが問題であれば、AlertDialogを使わない
方法で実現できないかと思い、AlertDialogで意思確認するのではなく、確認用レイア
ウトで意思確認するよう修正してみました。
setContentViewで確認用レイアウトに切り替えて、そのレイアウト内のOKボタンが押
下されたら、deleteDataメソッドを呼ぶ形にしてみたのですが、deleteDataメソッド内の
ProgressDialogは表示されませんでした。
さらに、その確認用レイアウトのOKボタンが押下されたら、setContentViewで削除処
理中レイアウト(ProgressDialogをレイアウトXMLで記述)に切り替えた後、deleteData
メソッド(ProgressDialogのコードは削除)を呼ぶ形も試してみたのですが、deleteData
メソッドが先に実行され、その処理が終わった時点で削除処理中レイアウトに切り替わ
りました。
deleteDataメソッドは、単にSharedPreferenceでputInt、putString、remove等を実行し
ているだけのものですが、何故このような動きになるか分かりません。
毎度申し訳ありませんが、問題点をご指摘頂けたら幸いです。

よろしくお願いいたします。
> > > > <android-gro-up-japan%2Bunsu...@googlegroups.com<android-gro-up-japan%2-52Buns...@googlegroups.com>
>
> ...
>
> もっと読む ≫- 引用テキストを表示しない -
>
> - 引用テキストを表示 -

夜子まま

unread,
Aug 22, 2010, 11:25:06 AM8/22/10
to android-g...@googlegroups.com
夜子ままです

Androidの画面処理はちょっとわかりづらいようにおもうけど、ポイントを押さえれば
すぐわかるとおもいます。

間違いを恐れないで言ってみると、ひとつのスレッドないで画面描画処理のイベント
も実行されているので、そのスレッド内で処理をとめていたら描画はされません。

だからとあるイベントが発生して、そのイベント内でdeleteDataを呼び出し、そして
deleteDataの中からProgressBarを表示するプログラムを書いても
deleteDataの処理から抜けてWindowの描画処理をするところに処理を返してあげないと
描画されないのです。

これを描画させるために、重たい処理をするDeleteDataを別のスレッドにしましょう。
この場合、単純にThreadクラスをつかってこれをスレッドにしてもいいのですが
AsyncTaskだとスレッド処理ないで同期メソッドを呼んでくれる便利なクラスなので、
それを大崎さんは説明してくれていました。
ProgressBarは進捗状況を定期的に指定する処理をするので同期処理のところで
カウントアップするといいです。

ちょっとわかりにくいですね、、すみません、もっとわかりやすい説明をしてくれる方がでてくる
ことを祈りつつ、、

※スレッド : CPUの処理の単位
プログラムは上から順番に実行されていきます、その動いている処理をメインスレッドとし、それと
平行に動作する処理をサブスレッドといいます。
Eventがよばれたとき、そのイベント処理をメインスレッドとした場合、重たい処理(delteData)は
サブスレッドになります、スレッド同士は同時に動いているのでスレッドで共有している変数を
書き換えると予期しない問題が発生します、それをガードするためハンドラーという仕組みを
つかって安全に書き込みができるようにしています。


以上、どっか間違えてるんじゃないかとひやひやしながら説明してみた。



2010年8月23日0:02 micco <gou...@gmail.com>:
このグループから退会するには、android-group-j...@googlegroups.com にメールを送信してください。
詳細については、http://groups.google.com/group/android-group-japan?hl=ja からこのグループにアクセスしてください。


micco

unread,
Aug 23, 2010, 9:21:02 AM8/23/10
to 日本Androidの会

こんばんは。
miccoです。

>夜子ままさん
解説ありがとうございます!
非常に参考になります。

>重村さん、夜子ままさん、大崎さん
まだ勉強不足でメインスレッド内での画面描画のスケジューリング等の
仕組みを理解できていないですが、重い処理でメインスレッドがとめられ
て、画面描画のイベント(内部的には、invalidateの定期呼び出しでしょ
うか?)が実行できず、画面が更新されない現象が起こっているというこ
とは認識できました(正しく認識してないかもしれませんが^^;)。
今後マッシュアップを考えるなら、非同期処理は必要になるでしょうから、
これを機にAsyncTaskを勉強してみようと思います。
なかなか便利そうですが、私の持っている4冊の参考本には一切記述
がありませんでしたw
AsyncTaskの実装で分からないことがありましたら、また質問させて頂
きます。

引き続きよろしくお願いいたします。

micco

unread,
Aug 23, 2010, 10:43:29 AM8/23/10
to 日本Androidの会
こんばんは。
miccoです。

以下のとおり実装したところ、データ削除処理中にきちんとプログレスダイア
ログが表示されました。ありがとうございました!

Javaの基礎知識が欠落していますので、オーバーライドするメソッドの引数
の型宣言が「void」ではなく「Void」である意味や「Void... params」の「...」
の意味等よく理解できていない部分もありますが、ひとまずおまじないとい
うことで使います^^;

もっとJavaの基礎を学んだ方が良さそうです。
ご協力ありがとうございました。

public void onClick(View view)
{
AlertDialog.Builder ad = new AlertDialog.Builder(this);
ad.setTitle("確認");
ad.setMessage(全データを消去します");
ad.setPositiveButton("キャンセル",new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface di,int which_button)
{
//何もしない
}
});
ad.setNegativeButton("消去",new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface di,int which_button)
{
BackgroundTask task = new BackgroundTask(A1.this,"データ消去中","しばらくお待ち下さ
い");
task.execute();
}
});
ad.create();
ad.show();
}

public class BackgroundTask extends AsyncTask<Void,Integer,Boolean>
{
private Context context = null;
private ProgressDialog dialog = null;
private String title;
private String msg;
public BackgroundTask(Context context,String title,String msg)
{
this.context = context;
this.title = title;
this.msg = msg;
}
//処理実行前メソッド
protected void onPreExecute()
{
//プログレスダイアログ設定
dialog = new ProgressDialog(context);
dialog.setIndeterminate(true);
dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
dialog.setTitle(title);
dialog.setMessage(msg);
dialog.show();
}
//処理実行中メソッド
protected Boolean doInBackground(Void... params)
{
//データ消去処理
deleteData();
return true;
}
//処理実行後メソッド
protected void onPostExecute(Boolean result)
{
//プログレスダイアログ消去
dialog.dismiss();
Reply all
Reply to author
Forward
0 new messages