読者です 読者をやめる 読者になる 読者になる

高見知英のかいはつにっし(β)

高見知英のアプリケーション開発日誌 のほか、地域活動などの活動報告ブログ。

Androidプログラミングデビュー

先週の週末に、ちょっとだけAndroidプログラミングをやりました。ちょうど習作に良さそうな題材が思いついたので、メインのPCに環境をセットアップしてプログラミング。

ちなみに、教科書に使ったのはこちら

Google Androidアプリケーション開発入門 画面作成からデバイス制御まで――基本機能の全容

Google Androidアプリケーション開発入門 画面作成からデバイス制御まで――基本機能の全容


ここに載っている内容については、特に用語の説明なく出してしまいますので、そのつもりで。


さて、内容としては。ひとまず写真のような感じ。

個人的に使うカウンタアプリです。一応複数のカウンタをもてるようにしてみました。とはいえ、まだまだ作りかけですが。


今回扱った課題は、以下。

  • ListView
  • アダプタクラスを自作する(独自に作成したクラスでは標準のArrayAdapterが使えないため、アダプタクラスを自作する必要がある)
  • メニューを作成する
  • AlertDialogにカスタムビューを設定する

課題の分類は適当に。習作中の習作でしたが読んでいる方の参考になれば幸いです。

ListView

ListViewは、その中にあらかじめ指定したビューを複数格納できる、ちょっと特殊なビューです。WindowsのListViewなどとは違い、中に自分の好きなビューを設定することができるため、なかなか汎用性が高いビューです。


本にはListActivityを継承したアクティビティを使ったプログラム例が記載されていますが、なんか奇妙な感じだったので、ふつうにActivityを継承したクラスでやりました。

  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    items = new ArrayList<CounterItem>();
    adapter = new CounterAdapter(this, this.getApplicationContext(),
        R.layout.list_row, items);
    cList = (ListView)findViewById(R.id.list_view);
    cLabelNoItem = (TextView)findViewById(R.id.label_is_empty);
    cList.setAdapter(adapter);
  }

ListActivityでないと不便なところはこの先出てくるのかもしれませんが、ひとまずはこれで問題なしのようです。

手順としては、以下のような感じ

  • データを保持するArrayListを用意する
  • ListViewとArrayListを結びつけるアダプタを用意する
  • アダプタとListView自体を関連づける(setAdapterメソッドを呼び出す)

以後、ListViewの内容を削除したり追加したりするときには、アダプタクラスを操作します。データを保持するArrayListを操作しても画面表示は即時には変わらないので注意です。

アダプタクラスを自作する

上のコードにも少し出ていますが、StringやIntegerなど、組み込みのクラス以外のクラスを格納したArrayListを使う場合、標準のArrayAdapterは使えません。
よって、ArrayAdapterを継承して独自にクラスを作る必要があるようです。

アイテムクラス
public final class CounterItem {
  private Integer counter;
  private String name;

  public CounterItem(String name, Integer counter) {
    this.name = name;
    this.counter = counter;
  }
  
  // … getterとsetterの宣言 …
}
アダプタクラス
public class CounterAdapter extends ArrayAdapter<CounterItem> {

  private Activity owner;
  private ArrayList<CounterItem> items;
  private LayoutInflater inflater;

  public CounterAdapter(Activity owner, Context context, int textViewResourceId,
      ArrayList<CounterItem> objects) {
    super(context, textViewResourceId, objects);
    this.owner = owner;
    this.items = objects;
    this.inflater = (LayoutInflater) context
        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  }

  @Override
  public View getView(int i, View view, ViewGroup viewgroup) {
    if (view == null) {
      view = inflater.inflate(R.layout.list_row, null);
    }
    final CounterItem item = items.get(i);
    if (item != null) {
      ((TextView) view.findViewById(R.id.label_counter_name)).setText(item
          .getName());
      // … 以降、アイテムの設定 …
    }
    return view;
  }
}

基本的なところはArrayAdapterで実装済みなので、アダプタクラスではgetViewメソッドだけ実装してやればいい。getViewメソッドでは、あらかじめ作っておいたlistViewの行用に作ったレイアウトのXMLを読み込ませて、その各コントロールに文字列などの値を設定します。

ビューの操作方法はActivityクラスと同じですが、Activityクラスと違ってこちらはContextを持っていないので、AlertDialogなどを表示したいときにはContextを上から(ここではコンストラクタの引数ownerとして、親のActivityの参照を格納するようにしています)とってくる必要があります。

メニューを作成する

XMLをメニュー表示時に読み込ませて一発。便利ですね。
メニューが押されたときのイベントは、onOptionMenuSelectedメソッドで取得できます。この辺はWindowsと一緒なので対して迷いません。


なお、このときのメニューアイコンには、もちろんシステムリソースにはいっているアイコンも使えます。そのときはアイコンのIDに@android:drawableから始まるIDを指定すればいいのです(「ic_menu_add」なら「@android:drawable/ic_menu_add」)。
どんなアイコンがどんなIDを持ってるかはTaosoftwareさんの記事が参考になります。

AlertDialogにカスタムビューを設定する

画面全体を占有しないダイアログを表示するには、AlertDialogを使います。
しかし、これだけではテキストとボタンのみのダイアログしか表示できませんので、カスタマイズができません。
そんなときは、AlertDialog.Builderクラスを使って、独自のダイアログを作ることができます。

さらに、このダイアログでは、自分の好きなビューを当てはめて使うことができます。たとえば、EditTextビュー(テキストボックス)をはめて簡単な入力プロンプトを作るとか。

  AlertDialog.Builder dlgbld = new AlertDialog.Builder(owner);
  dlgbld.setTitle(R.string.caption_delete);
  dlgbld.setMessage(R.string.caption_query_delete);
  dlgbld.setCancelable(true);
  dlgbld.setPositiveButton(R.string.OK, new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dialog, int which) {
      Main m = (Main)owner;
      m.removeCounter(item);
    }
  });
  dlgbld.create().show();

感想

はじめてAndroidプログラミングをやって

GWTのプログラムをさわったときにも感じましたが、感じとしては本当にHTML+Javascriptのプログラミングににているなと思いました。IDを指定してコントロールをビューからとってくるとか、モーダルダイアログ(表示している間コードの実行が停止するタイプのダイアログ。Windowsプログラミングではわりと標準)がなかったりと、Javascriptのプログラミングと流儀がにている。
おかげで最初は戸惑ったものの、わりとすんなりプログラミングができた。半日弱しかコーディングしてないのにここまでできたのも、こういう仕組みだからだろうと思います。

レイアウトについては・・・

ちょっと難しいかも。思った通りにレイアウトはまだまだ難しい。HTMLのCSSと似た形で(という表現で、いいのかな?)レイアウトするので、CSSのレイアウトも理解し切れていないわたしにはちょっときつい。
まだまだ共に習熟が必要です。

Windows/Windows Mobileプログラミングと比べて

なにより、Windowsであれば結構作るのが手間な、複数コントロールを乗せたリストビューを標準機能で簡単に作れる、カスタマイズしたダイアログを一般的なダイアログと同じ感覚で表示できる という点がとても魅力的でした。
WindowsやWindows Mobileプログラムでは、前者はカスタムコントロールを作ったり、リストの管理を自前でやったりしないといけなかったし、後者はチェックボックス一つ作るのにもいちいちフォームとして作ってやる必要があった。それに比べるとかなり楽にプログラミングができるなあ と思います。
まだまだAndroidらしいアプリ越しのインテント送受信だったり、サービスや通知を使ったプログラムはやってないですが、なかなかやっておもしろいプログラム環境だなと思いました。
今後Windowsプログラムを作るときも、この流れ、やり方が参考になるかもしれませんね。