筆者はこのところ,めずらしく毎日コードを書いている。もちろん,雑誌の連載や特集のサンプルコードはいつも書いていたのだが,会社でやっているアプリ開発では,設計とクラスやサンプルコードを少し書くぐらいで,あとはプログラマにお願いしていた。

 しかし,ちょっとした事情が重なって,最近はCakePHPを使ってWebアプリをゴリゴリ書いているのだ。いや,CakePHPは良くできたフレームワークなので実際に「ゴリゴリ」書いているわけではない。CakePHPをはじめとするフレームを使うと,データベースからメモリーへ,逆にメモリーからデータベースへと項目の値を編集する力仕事的コーディングから,解放される。

 CakePHPでは,アプリの骨組みを自動作成(bake)して,独自に必要な機能をちょこちょこと追加していけばよい。もちろん,オブジェクト指向なので,親のクラスのメソッドをオーバーライドして,ドーンと動作を変更といったプログラマ的全能感を味わうこともできる。

 そういう意味では,集中力や持続力の落ちた筆者のような中高年プログラマに優しい環境なのであるが,悩むのはどこに書けばいいのか,どこで直せばいいのかということだ。手を動かさないで,次の一手に悩んでいる時間が多い。

 アラウンド・フィフティの問題点,老眼対策としては27インチのハイビジョンのディスプレイを導入したが,もう一つ引っかかる点は,Ruby on Railsに似たCakePHPには約束事が多いことだ。

 Convention over Configuration(設定よりも規約)という方針で,自動的にO/Rマッピングする方法は,たしかにデータベース・プログラミングの退屈な部分を取り除いてくれる。しかし,テーブル名は,モデル名の複数形であり,sを付けるだけじゃダメで,厳密に英語の複数形にしなくてはいけないというルールは,言い尽くされてはいるが,やはり日本人には馴染みにくい。モデルとテーブルの関係をどこかに定義できればいいじゃないとついつい思ってしまう。もちろん,そんな考えをコントローラ,ビューまでに広げていくと,ややこしいことになってしまうのは理解できるのだが,それでも,やっぱりお仕着せは窮屈だ。もっと,自由に書きたいと思ってしまう。

 たまにCakePHPを止めて,Androidのプログラミングをしてみるが,隣の芝生は青いかというと,そうでもないようだ。前回(「第324話 測定した血圧をデータベースに記録する」)はデータベースに血圧の測定結果を登録した。今回はその測定結果を一覧表示する処理を作成する。日々,記録した血圧を医院で,先生に見せるというシナリオだ。AndroidではListViewクラスを使えば,簡単にデータバインドできる。しかし,簡単なものには規約がある。

--------------------------------------------------------------

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"> 
<!-- データ表示用のListView --> 
<ListView
  android:id="@android:id/list"
  android:choiceMode="singleChoice"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
/>
<!-- データが一件もないときに表示するTextView --> 
<TextView
  android:id="@android:id/empty"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="@string/empty"	
/>
</LinearLayout> 

--------------------------------------------------------------

 まず,view.xmlという表示用のレイアウトを作成する。上のリスト1にあるようにListViewのidは@android:id/listに決まっている。データが存在しないときに,表示するTextViewのidも@android:id/emptyに決まっている。そこまで決めなくてもよいように思うのだが,違うidにするとエラーになる。

--------------------------------------------------------------

public class bldPressView extends ListActivity {
  private DatabaseHelper dbhelper;
	
  private static final String[] COLUMNS =
  {"_id","max","min","pulse","date","time"};
	
  private static int[] TO = { R.id._id, R.id.max, 
       R.id.min, R.id.pulse, R.id.date, R.id.time};
    @Override
    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.view);
      dbhelper = new DatabaseHelper(this);
      Cursor cursor = getAll();
      showAll(cursor);
    }
    private Cursor getAll(){
      SQLiteDatabase db = dbhelper.getReadableDatabase();
      Cursor cursor = db.query("bldpress2", COLUMNS, null, 
       null, null, null, "_id DESC");
      startManagingCursor(cursor);
      return cursor;
    }
    private void showAll(Cursor cursor) {
      SimpleCursorAdapter adapter = 
          new SimpleCursorAdapter(this,
        R.layout.row, cursor, COLUMNS, TO);
      setListAdapter(adapter);
    }
}

--------------------------------------------------------------

 上のリスト2が今回作成した一覧表示用のクラスだ。getAll()では,読み込み用にデータベースを開いて,queryでテーブルを読み込み,cursorを返す。

 showAll()が問題だ。SimpleCursorAdapterにパラメータを,this,1行のレイアウト,cursor,テーブルの項目,レイアウトの項目の順で渡し,adapterを作成してsetListAdapterでListViewにセットするのだが,SimpleCursorAdapterを使うときは,テーブルのid項目の名前は_idでなければならない。これも規約であるが,もう少しゆるくてもいいのじゃないかと思ってしまう。前回作成したbldpressテーブルでは主キーの名称をrowidにしていたので,今回はテーブルを作り直した。

--------------------------------------------------------------

<string name="empty">血圧データが登録されていません</string>

--------------------------------------------------------------

 文字列を定義するstring.xmlに、上記のリスト3のようにemptyのときのメッセージを追加したので,レコード登録前の一覧を実行すると,以下のように表示される。

 説明の順序が逆になってしまったが,登録画面には一覧ボタンを追加し,以下のリスト4

--------------------------------------------------------------

Button btnView = (Button) this.findViewById(R.id.Button02);  
btnView.setOnClickListener(new OnClickListener(){  
  public void onClick(View v) {  
    Intent intent = 
       new Intent(bldPressInput.this, bldPressView.class);
    startActivity(intent);    		
  }  
});

--------------------------------------------------------------
のようにIntentクラスを使って,画面を遷移するようにリスナーを仕掛けてある(Intentについては「第310話 Intentを使ってダイアログを開く」,「第311話 複数の画面間でデータをやり取りする」あたりを参照してほしい)。
--------------------------------------------------------------

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="horizontal"
  android:padding="5px">
  <TextView
    android:id="@+id/_id"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
  />
  <TextView
    android:id="@+id/max"
    android:paddingLeft="5px"		
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
  />
  <TextView
    android:id="@+id/min"
    android:paddingLeft="5px"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
  />
  <TextView
    android:id="@+id/pulse"
    android:paddingLeft="5px"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
  />
  <TextView
    android:id="@+id/date"
    android:paddingLeft="10px"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
  />
  <TextView
    android:id="@+id/time"
    android:paddingLeft="5px"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
  />
</LinearLayout>

--------------------------------------------------------------

 さて,最後に説明すべきは,上のリスト5のrow.xmlだろう。1行の項目の配置が定義されているのだが,android:padding="5px"とした場合は,上下左右のpaddingとなる。個別に一方向だけ指定するときはandroid:paddingLeft="10px"のように記述する。

 表示結果は以下のようになる。このデータは適当に入力した値なのだが,上は薬でサッと下がるが,下がしぶとく高いというのが私の血圧の特徴である。