Boring Days as tech

金に生きるは下品にすぎる、 恋に生きるは切なすぎ、 出世に生きるはくたびれる。 とかくこの世は一天地六。 命ぎりぎり勝負をかける。 仕事はよろず引き受けましょう。 大小遠近男女は問わず、委細面談、仕事屋稼業。

CursorAdapterの基本

CursorAdapterについて日本語の解説が極端に少ないので書いてみた。
けどなんで少ないんだろう。。。確かにスゴイ使い勝手が良い訳ではないけど何か悪い点があるんだろーか。。。
結局大量のデータを簡単に列挙する方法ってそれ意外にない気がするし積極的に使って言っても良いかもしれないと思うんだけど。

CursorAdapterって何

Androidはちょっと大容量のデータをメモリにおくだけで不可避なOutOfMemoryエラーが発生する。
ともするとListViewなどで大量のデータを列挙をしたい場合(たとえばTwitterのタイムラインとか)だと、
メモリに保持しておく仕様だと表示する件数に限界が出てくる。列挙するデータの中に画像などが含まれたら余計にその件数は圧迫される。
で、SQLiteにデータを保持させ、そこから必要なときだけ動的にデータをSelectし、バインドさせる方法がある。
そうすることによりメモリの圧迫を抑え、膨大な件数を早い処理で画面に表示させることが出来る。
それを実現するクラスがCursorAdapterとなる。
勿論使い方は基本的に今までのAdapterと変わらない。

SimpleCursorAdapter

CursorAdapterを簡単に実装できるクラスとしてSimpleCursorAdapterがある。

SimpleCursorAdapter (Context context, int layout, Cursor c, String[] from, int[] to)

context:コンテキスト
layout:表示するレイアウトID
cursor:SQLiteからSELECTしたCursor
from:Cursorのカラム名
to:バインドする先のViewID


が引数となっており、fromとtoのlengthは同じでなければならず、お互いが対応関係になっている。
すなわちfromで1番目に指定したカラム名の値がtoで1番目に指定したViewにバインドされる形で反映される。
これはCursorのもつ値をそのまま表示する際にはとても楽であるけど、変換や処理をかませるときには使いにくいし、
Spinnerのような二つのレイアウト(DropDown時と通常時)を持つ場合も使いにくい。
ちなみにSpinnerでそのままSimpleCursorAdapterを使う場合は、
setDropDownViewResource(resourceId)で別にレイアウトIDを指定してあげる。
コンストラクタで指定したfrom、toの関係にDropDownViewも合わせなければならないので余計に面倒。

CursorAdapter拡張

んで、SimpleCursorAdapterの大元のCursorViewを拡張する。
CursorAdapterのCursorAdapterたる部分は以下二つのメソッドのOverride。

	@Override
	public void bindView(View view, Context context, Cursor cursor) {
		//newViewで作ったViewが引数として渡ってくるので、それに応じてバインドする
		TextView tv = (TextView)view.findViewById(R.id.text);
		tv.setText(cursor.getString(cursor.getColumnIndex(columnName)));
	}
 
	@Override
	public View newView(Context context, Cursor cursor, ViewGroup parent) {
		//初めて表示されるときに呼ばれる。ここでレイアウトを定義。
		View v = context.getLayoutInflater().inflate(R.layout.layout_id, parent)
		return v;
	}


Spinnerの場合は同じように以下二つも拡張
getDropDownView(int position, View convertView, ViewGroup parent)
newDropDownView(Context context, Cursor cursor, ViewGroup parent)


なお、Adapeterの保持データが変更したときにそれを画面に反映させるnotifyDataSetChanged()だが、
CursorAdapterの場合はAdapterからgetCursor().requery()を呼ぶことで、内部でnotifyDataSetChanged()が呼ばれる。

やっぱり使いにくい面も

Curosrをもとに列挙させるということは、素直に作るとイレギュラーな行を途中で挿入できないということ。
だからListViewの途中でヘッダー的なレイアウトを差し込むだとかは難しい。
単純に大量のデータを列挙する、という目的には有効だが、列挙する行が増減するような複雑な処理はできないの??