時間のかかる処理、例えばネットから何かをダウンロードするアプリを作る場合、「通信中」「ダウンロード中」などのダイアログを表示し、キャンセル可能な状態にした上で、別スレッドを起動して実際の通信処理を行うということがよくあります。
Androidなら、メインのActivityから時間のかかる処理を行うThreadを生成し、そのrun()の最後に、メインのActivityへ終了を通知、Activityはダイアログを閉じる、といった流れになるかと思いますが、androidでこのまま実装してしまうと「Only the original thread that create a view hierarchy can touch its view.」というエラーになってしまいます。
ようはActivity自身のスレッドのみがそのビューを変更できる、ということのようです。Androidはいちいちメッセージが丁寧でありがたいです。
じゃあAndroidではどうするのかということですが、Handlerクラスとそのpost()メソッドを使用します。
例えば、ActivityにRunnableを実装しておき、run()メソッドにはダイアログを閉じる処理を書いておきます。一方、時間のかかる処理を実行するThreadにはhandlerオブジェクトとRunnableを実装したActivityを渡します。そしてThread#run()の最後で「handler.post(activity);」とかすれば、処理の終了時にちゃんとダイアログを閉じることができます。
ソースコードにするとこんな感じ。
public class MyActivity extends Activity implements Runnable { private final Handler handler = new Handler(); private ProgressDialog dialog; // 中略 private void doSomething() { // プログレスダイアログを表示 dialog = new ProgressDialog(this); dialog.setIndeterminate(true); dialog.setMessage("Now in progress."); dialog.show(); // 時間のかかる処理を実行するスレッドをスタート doSomethingThread = new DoSomethingThread(handler, this); doSomethingThread.start(); } public void run() { // ダイアログを閉じる dialog.dismiss(); } } public DoSomethingThread() extends Thread { private Handler handler; private final Runnable listener; public DoSomethingThread(Handler _handler, Runnable _listener) { this.handler = _handler; this.listener = _listener; } @Override public void run() { // 時間のかかる処理 // 終了を通知 handler.post(listener); } }
以上、こちらの記事に書いてあることをかみ砕いてみました。
イマドキのAndroidアプリケーション開発方法