AndroidでModalなDialogがほしいー。と思ったことがある人も少なくないと思う。
ModalDialogってMFCとかではあったけどAndroidにはない。AndroidだとAlertDialogとかを使ってYES/NOのDialogを表示したとしても、結果を取得するためにListenerを書かなければいけないし、必ず非同期になる。非同期で取得した結果から処理を分岐させたいときには、そのListenerの中で処理を記述しなければならない。こうすると関数のネストが深くなりがちになる。まあ、関数分ければいいだけの話だけど、いちいち他の関数に飛ぶのもなー。ということでModalなDialogが欲しくなる。
ModalDialog dialog = new ModalDialog();
int result = dialog.show();
のように書いたら結果が同期で帰ってくるようなやつ。
で、作ってみようかと思た。
結論だけ書くと無理だった。。。
java.util.concurrent.CountDownLatch
を使ってthread止めればいけんじゃね?とかおもったけど、
mStartSignal.await();
でUIのThread止めちゃうとイベントリスナーのコールバックが帰ってこないのだ。。。
まあ、ListenerもUIスレッドで動いているから当たり前ですよね。。。
やっぱAndroidって動きがシングルスレッドっぽいよね。
ただ、かなりインチキ臭いけど回避策もある。ModalDialogの呼び出しをUIスレッド以外で行えばいいのだ!そうすれば同期でコールできる。
でも呼び出し元はこうなる。
public class ModalDialogActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button btn = (Button) findViewById(R.id.start);
btn.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View v) {
final Context c = v.getContext();
new Thread(new Runnable() {
@Override
public void run() {
final int result = ModalDialog.show(c);
ModalDialogActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast toast;
switch (result) {
case ModalDialog.YES:
toast = Toast.makeText(c, "YES", Toast.LENGTH_SHORT);
break;
case ModalDialog.NO:
toast = Toast.makeText(c, "NO", Toast.LENGTH_SHORT);
break;
case ModalDialog.CANCEL:
default:
toast = Toast.makeText(c, "CANCEL", Toast.LENGTH_SHORT);
break;
}
toast.show();
}
});
}
}).start();
}
});
}
コールした結果をToastで出すだけなのに、すげー深くなったww
まあ、教訓としてはAndroidではCountDownLatchを極力使わないほうがいいし、もし使うならLooperが絡んでいるThreadでは呼んじゃだめってことくらいか。
まあ、Androidの場合はCountDownLatchを使いたくなる機会ってほぼないとは思うけど。

0 件のコメント:
コメントを投稿