このページの本文へ

前へ 1 2 3 4 5 次へ

これで作れる! Androidのアプリケーション 第8回

Androidアプリに必要なダイアログを作る

2010年08月20日 12時00分更新

文● 塩田紳二

  • この記事をはてなブックマークに追加
  • 本文印刷

別スレッドで処理して
メインスレッドではダイアログを表示する

 このため、ProgressDialogを使うためには、時間のかかる処理を別スレッドで実行させ、メインスレッドでは、ProgressDialogを表示させるといった構造を作る必要があります。ここだけを見ると、ダイアログを表示させるのに別スレッドを作るのは、本末転倒な感じもしますが、ANRを起動させないためにも別スレッド化が必要だし、GUI側で画面を更新(ProgressDialogはアニメーションが動作する)させるためにも必要な構造なのです。

 以下のリストは、タイムゾーンのリストを都市名順に並び変える部分のコードです。EditItem.javaの464行目からに相当します。タイムゾーンのリストはかなりの数が定義されており、並び変えには少し時間がかかるため、別スレッド(DoSort)で実行させ、その間にProgressDialogを表示しています。

private void imsort(){
  dialog = new ProgressDialog(this);
  dialog.setIndeterminate(true);
  dialog.setMessage(myS(R.string.sort_wait));
  dialog.show();
  tmpsort = new DoSort(handler,this);
  tmpsort.start();
}

private class DoSort extends Thread {
  private Handler handler;
  private final Runnable listener;
  public DoSort(Handler _handler, Runnable _listener){
    this.handler = _handler;
    this.listener = _listener;
  }
  @Override
  public void run()
  {
    WorldClock.myTimeZoneData.sort_by_city();
    handler.post(listener);
  }
}

 スレッドはjavaのスレッドです。Threadクラスを継承するDoSortクラスを作り、その中のrunメソッドに処理を記述します。

 このコードが別スレッドで実行されているとき、メインスレッドは、ProgressDialogを呼び出している状態です。これを止めなければなりません。このためのコードが「handler.post(listener);」です。前述のように別スレッドからは、GUI操作を行なうことはできません。ということは、ProgressDialogを止めることもできないのです。サブスレッド自体は、処理が終われば停止しますが、何らかの方法で、GUIを表示させているメインスレッドを実行させないと、ダイアログを止めることができないのです。ところが、メインスレッドはProgressDialogのshow()を実行した状態なので、アプリケーションには戻ってきていない状態になっています。

 そこでHandlerを使って、ProgressDialog.show()を実行中のメインスレッドに割り込みをかけて、ダイアログを止めるような処理を行なわせているのです。実際には、EditItem.javaの454行目にあるrunメソッドが呼び出されます。

public void run(){
  MyListAdapter arrayAdapter = new MyListAdapter(this,WorldClock.myTimeZoneData.getTimeZoneDb());
  arrayAdapter.setCityNameMode(true);
  tzlist.setAdapter(arrayAdapter);
  tzlist.invalidate();
  tzlist.setSelection(WorldClock.myTimeZoneData.blute_search(getTimeZone()));
  dialog.dismiss();
}

 というのは、listnerには、自分自身(this)が指定してあるからです。実はEditItemは、ActivityであるとともにRunnableでもあります。51行目の宣言では、

public class EditItem extends Activity implements Runnable

としてあります。

 Runnableであるthisに対して、Handler.post(listener)を実行すると、EditItemクラスのrunメソッド(DoSortクラスにもrunメソッドがあることに注意)が実行されるわけです。

 本当は、thisを使わずに別途Runnableクラスを作り、そのなかにrunメソッドと同等な処理を記述しておいて、これをスレッドに引数として渡し、スレッド内でHandler.postメソッドを使って起動するというのが、正しいやり方なのでしょうが、スレッドはここ1つだけでもあり、記述を簡単にするためにEditItemをRunnableにしてしまいました。

 Handlerクラスは、Androidのオブジェクトです。内部にキューを持っていて、キューに入ったRunnableなオブジェクトを順番にメインスレッドで実行するものです。これが用意されているのは、前述のようにメインスレッドだけがGUI操作が可能なため、今回のProgressDialogのような操作を別スレッドから行なうためなのです。

 では、上のリストからEditItemクラスのrunメソッドを見てみましょう。ここでは、EditItemにあるリストを更新して、最後にdialog.dismiss()を実行しています。dialogは、ProgressDialogなので、これで表示されているProgressDialogが止まり、メインスレッドに戻ってきます。

 さて、次回はAndroidのGUIパーツの中でも一番複雑なListViewについて解説する予定です。

前へ 1 2 3 4 5 次へ

カテゴリートップへ

この連載の記事

注目ニュース

ASCII倶楽部

プレミアムPC試用レポート

ピックアップ

ASCII.jp RSS2.0 配信中

ASCII.jpメール デジタルMac/iPodマガジン