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 件のコメント:
コメントを投稿