このページの本文へ

前へ 1 2 次へ

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

Androidアプリで複数の項目を表示するリストビューを使う

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

文● 塩田紳二

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

ListViewの表示内容を変える

 ListViewを使うとき、条件によっては、一回設定した配列とは違う内容の配列を表示させたくなることがあるでしょう。このような場合には、新たなArrayAdapterを生成して割り当てます。そして最後にinvalidateメソッドを使ってListViewを強制的に再描画させます。これはEditItem.javaでは、「go_listByArea」メソッド(ボタンを押したときに呼ばれる)の中にある「onClick」メソッドでこの処理を行なっています(405行目から)。

 ここではリストを都市名でソートし、MyListAdapterに対して「setCityNameMode」を実行して、表示方法を変えさせています。通常では、ListViewにTimeZone IDがそのまま表示されるのですが、この場合には、エリアを限定して都市名でのみ表示することにしているので、エリア名を外し(最初の/の前を削除)し、アンダーバーをスペースに変換しています(297行目)。

ListViewのイベントを処理する

 ListViewは、複数あるものの中から選択するためのもので、ユーザーが何を選択したのかは、どれがタップされたのかなどで検出します。実際には2つのイベントリスナーが必要で、1つは直接タッチしたり、トラックボールなどを押し込んだときに発生する「OnItemClick」で、もう1つはトラックボールなどのポインティングデバイスで項目が選択されたときに発生する「OnItemSelected」です。ポインティングデバイスを持たないAndroid機では、前者しか発生しませんが、トラックボールなどを持つ機種では、リストの項目がトラックボールなどの動きに合わせて選択状態となります。

 世界時計サンプルでは、選択状態のときにも、TimeZone IDを表示するTextViewに選択されたTimeZoneIDを表示するようになっています。今回は、リストビューを含めたAndroidプラットフォームの性能を試すいう部分もあったので、両方のイベントを処理させています。

 具体的にコードを見てみることにしましょう。以下のリスト03がListViewのイベントリスナーである「onItemClickListener」の定義です。

リスト3

tzlist.setOnItemClickListener(
    new AdapterView.OnItemClickListener() {
      @Override
      public void onItemClick(AdapterView<?> parent,
          View v, int pos, long id) {
        ListView lv = (ListView) parent;
        String item = (String) lv.getItemAtPosition(pos);
        timezone.setText(item);
        lv.setSelection(pos);
        lv.setSelected(true);
        retIntent.putExtra(myS(R.string.Extra_timezone),
          getTimeZone().trim());
      }
    }

 ここでは、処理が簡単なものであるため、無名クラスを使い「setOnItemClickListener」の引数のところで直接イベントリスナーを定義しています。無名クラスによる定義は、このようにオブジェクトに対してあとからリスナーなどを設定するようなときに、わざわざ名前を考えることなく、その場で定義ができるのがメリットですが、半面、カッコが多く複雑なステートメントになってしまいます。このリストでは、全体が1つのステートメント(最後のカッコの後ろに行末記号であるセミコロンがある)になっています。定義するイベントリスナー内部の処理が単純なときには有効なのですが、あまりに大きいときには、分離したほうがコードを読みやすくなります。

 内部で定義している「onItemClick」メソッドは、クリックされた項目(posで指定される)からTimeZone IDを取り出し、テキスト入力欄(timezone)に、文字列として設定しています。また、ListView自体に選択状態を表示させるようにsetSelection、setSelectedを実行しています。ListViewで選択された項目をハイライト表示させるには、この2つのメソッドを実行する必要があります。setSelectionを指定することで、リストは選択された項目を表示範囲の先頭に来るように表示し、setSelectedを指定することで選択項目をハイライト表示します。どちらか片方だけではダメで、この両方のメソッドを実行しないと、リストをハイライト表示のままにしておくことができません。

 なお、ListViewがフォーカスを得ていない状態では、ハイライト表示をしないので(別途設定すれば不可能ではありません)、外部からListViewの表示状態を制御するときには、setSelectionのみを実行すれば、選択された項目が先頭に表示されるようになります。これは、都市名の検索機能で使っています。

 最後にある「retIntent.putExtra……」はインテントから戻るときの設定値を指定するものです。EditItemアクティビティは、インテントで呼び出されるため、ユーザーのバックキー操作などでメインアクティビティに戻ります。このため、アプリケーション側からは、戻るタイミングを予測できないため、ListViewがクリックされ、その時点でのTimeZone IDが確定した時点で戻り値をここで設定しているわけです。

 もう1つのイベントリスナーがリスト4です。こちらは、前述のようにトラックボールなどのポインティングデバイスによるListViewの選択を処理します。onItemClickListenerと同様に無名クラスでの定義なのですが、「OnItemSelectedListener」では、内部で2つのメソッド「onItemSelected」と「onNothingSelected」を定義しなければなりません。前者は、ポインティングデバイスの移動で新たな項目が選択されたときに呼び出され、後者は、選択する項目がなにもない(たとえば、リスト項目がなにもないときなど)に呼び出されます。通常は「onItemSelected」だけを処理すれば問題ありませんが、中身は空でも「onNothingSelected」を定義しておかねばなりません。

 イベントリスナー内部の処理は、クリックの場合と同じですが、ListViewのハイライト表示などの処理はしません。というのは、ポインティングデバイスによる選択の場合には、システム側でハイライト表示をしてくれるのと、選択項目を先頭にするとギクシャクした動きになってしまうからです。

リスト4

tzlist.setOnItemSelectedListener(
  new AdapterView.OnItemSelectedListener() {
  @Override
  public void onItemSelected(AdapterView<?> parent,
      View v, int pos,long id) {
    ListView lv = (ListView) parent;
    String item = (String) lv.getSelectedItem();
    timezone.setText(item);
    retIntent.putExtra(myS(R.string.Extra_timezone),
      getTimeZone().trim());
    }
  @Override
  public void onNothingSelected(AdapterView<?> arg0) {
    }
  }
);

Androidによる処理は意外に高速

 AndroidではJavaでアプリケーションを開発します。実行は、機械語コードではなく、Dalvik VMと呼ばれる仮想マシンの仮想コードです。Dalvikは一般のJavaと違って、レジスタを複数持つCPUの命令セットに似た「レジスタマシン」となっているほか、必要なライブラリを実行前にリンクしてしまうなどの機能があり、高速に立ち上がり、実行も高速に行ないます。

 とはいえ、仮想コードなので、機械語コードに比べるとオーバーヘッドはあるはずです。こうしたスクロールしながら、TextViewを更新していく程度の処理がどの程度の負荷になるのかを調べたいという気持ちもあり、あえてトラックボールなどでリストを選択状態にすると、テキストボックス側も更新するようにしてみました。実機上でこれを動かしてみて、その反応を見れば、どの程度までの処理ならアプリケーションでやっていいかのあたりが付くと考えたわけです。バージョンなどによって違いますが、TimeZone IDの数は数百個(エミュレーターだと、558個)程度あり、Androidのような小さな画面に表示するにはかなり大きな項目数になり、全体を見るためにはかなりスクロールさせなければなりません。

 このコードはNexus Oneなどの高速なプロセッサ(1GHz動作のSnapdragon)を使う機種では、ほとんど問題を感じないレスポンス速度になります。これに比べるとかなり性能が劣るプロセッサ(528MHz動作のARM11相当)を採用するHT-03Aでも、トラックボールによるListViewのスクロールにはかなり追従します。あまり激しく動かすと、途中の表示が省略されることもあるようですが、トラックボールを止めるとスクロールもぴたりと止まります。ただ、画面右側のノブを使うFast Scrollの追従はHT-03Aでは、イマイチで、あまり大きなリストをスクロールさせて項目を探させるのはちょっと無理があります。

 そういうこともあり、WorldClockではTimeZone IDを地域別に表示する機能をつけてあります。TimeZone IDは「地域/都市名」という形式で、地域にはAmericaやAsia、Europaといったものがあります。TimeZone IDのリストを地域別にすることで、表示する都市名の数を減らして、探しやすくしているのです。

前へ 1 2 次へ

カテゴリートップへ

この連載の記事

注目ニュース

ASCII倶楽部

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

ピックアップ

ASCII.jp RSS2.0 配信中

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