Android 3.0より、Loaderを使ってデータをロードしなさいということで、Cursorの管理をstartManagingCursorに任せるのは非推奨になっているので、CursorLoaderについての記事をテクブ本を見ながら理解しようと思っていたら、CursorLoaderはContentResolverのLoaderのため、単純にsqliteのデータをロードするにはどうすればいいのかがわからなかった。
Loaderについて読んでいると、AsyncTaskLoaderを継承して処理を定義するとか。
参照URL
AsyncTaskLoaderは、AsyncTaskをさらに使い勝手をよくしたものであるということはわかった。AsyncTaskはonPreExecuteやonPostExecuteでUIに絡む処理を行なうため、どうしてもインナークラスになり易く、かつActivityクラスとの結合度が高いものになりがちである。
そこを、AsyncTaskLoaderだと、AsyncTaskのdoInBackGroundの処理のみに限定して処理させるような形。ActivityまたはFragment側で使うローダーをロードし、ローダーのコールバックメソッドを実装することで、UIの処理をActivityまたはFragment側に持たせる。これで、AsyncTaskLoaderに非UIの処理を、ActivityまたはFragmentにUIの処理を任せることができるので、ローダーの再利用性も増すし、役割の分離もたやすいと。
Loaderのロードは、ActivityのonCreateか、FragmentのonActivityCreatedで行なう。
sqlite用のローダーは、既にライブラリが公開されていたので、自分はそれを使わせてもらうことにした。
https://gist.github.com/1217628
SimpleCursorLoaderクラスは、抽象クラスになっているので、loadInBackgroundメソッドで取得したいカーソルを取ってきてリターンするだけの実装を継承したクラスで行なえばよい。楽だ。
サンプルとして載せておく。
まずはSimpleCursorLoaderを継承しているMyCursorLoader。
public class MyCursorLoader extends SimpleCursorLoader {
public MyCursorLoader(Context context) {
super(context);
}
@Override
public Cursor loadInBackground() {
// DBHelperはデータベースを扱うクラス
DBHelper dbHelper = DBHelper.getInstance(getContext());
Cursor cursor = dbHelper.findAll();
return cursor;
}
}
次に、MyCursorLoaderを使っているListActivity。
public class SampleList extends ListActivity implements LoaderManager.LoaderCallbacks<Cursor> {
private SimpleCursorAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sample_list);
mAdapter = new SimpleCursorAdapter(this,
android.R.layout.simple_expandable_list_item_1,
null, // Cursorが空のアダプタを作る
new String[]{DatabaseColumn.NAME}, // 適当なデータ
new int[]{android.R.id.text1},
0);
setListAdapter(mAdapter);
// ローダーをロードする
// idを0に、Bundleをnullに、コールバック実装は自身のクラスにしている
getLoaderManager().initLoader(0, null, this);
}
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// getLoaderManager().initLoaderで受けたidとBundleはここで受け取る
// 複数ロードしたりする場合はidで処理を分ける
// ここでは簡単にSimpleCursorLoaderを継承したMyCursorLoaderを返す
return new MyCursorLoader(this);
}
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
mAdapter.swapCursor(cursor);
}
public void onLoaderReset(Loader<Cursor> loader) {
mAdapter.swapCursor(null);
}
}
cursor.requery();の代わりが、
getLoaderManager().restartLoader(0, null, this);
になると思うので、データの編集が終った後等はこれを呼べばよいと思う。
ListViewなどで各行がクリックされたときの処理を行なう際に、Loaderからデータベースの情報を取れるのか、それとも、mAdapter.getCursorでカーソルを取ってそこから処理をするのかが今のところよくわかってない。現在は後者にしているが、それが正しいのか自信があんまりない。
あとrestartLoaderはonResumeなどでも呼んだほうがいいのだろうか?なども今のところ疑問点。変化があったら更新されるとか書かれていたのだが、データを更新しても表示状は更新されてなかったので、やはり明示的に呼ぶべきなんだろうか?そのあたりも後日調べていきたい。