特に重いクエリは使ってないんだが、とりあえずAsyncQueryHandlerを使ってSQLiteのクエリを非同期で処理する。
■実装
以下のようにmanifestファイルのapplication要素内にproviderを追加する。
<provider
android:name=".Provider"
android:authorities="info.justoneplanet.android.sample.provider"<!--アクセスするためのURI-->
android:exported="false"/><!--非公開にしないと他のアプリからアクセスできてしまう-->
セキュリティには注意する。
Helper.java
class Helper extends SQLiteOpenHelper {
private static final int VERSION = 1;
private static final String FILENAME = "info.justoneplanet.android.sample.db";
static final String TABLENAME = "tbl";
static final String ID = "_id";
static final String CREATED = "created";
static final String NAME = "name";
static Helper INSTANCE = null;
private Helper(Context context, CursorFactory factory) {
super(context, FILENAME, factory, VERSION);
}
public static Helper getInstance(Context context, CursorFactory factory) {
if (INSTANCE == null) {
INSTANCE = new Helper(context, factory);
}
return INSTANCE;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(
"CREATE TABLE `" + TABLENAME + "`(" +
" `" + ID + "` INTEGER PRIMARY KEY AUTOINCREMENT," +
" `" + CREATED + "` INTEGER," +
" `" + NAME + "` TEXT" +
");"
);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
Provider.java
以下のようにContentProviderクラスを継承したProviderクラスを作る。
public class Provider extends ContentProvider {
@Override
public String getType(Uri uri) {
return null;
}
@Override
public boolean onCreate() {
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
Helper helper = Helper.getInstance(getContext(), null);
SQLiteDatabase sdb = helper.getReadableDatabase();
Cursor cursor = sdb.query(
Helper.TABLENAME,
new String[]{Helper.ID, Helper.NAME, Helper.CREATED},
selection,
selectionArgs,
null,
null,
sortOrder,
null
);
return cursor;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
Helper helper = Helper.getInstance(getContext(), null);
SQLiteDatabase sdb = helper.getWritableDatabase();
sdb.insert(Helper.TABLENAME, null, values);
getContext().getContentResolver().notifyChange(uri, null);
return null;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
Helper helper = Helper.getInstance(getContext(), null);
SQLiteDatabase sdb = helper.getWritableDatabase();
int rows = sdb.update(Helper.TABLENAME, values, selection, selectionArgs);
getContext().getContentResolver().notifyChange(uri, null);
return rows;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
Helper helper = Helper.getInstance(getContext(), null);
SQLiteDatabase sdb = helper.getWritableDatabase();
int rows = sdb.delete(Helper.TABLENAME, selection, selectionArgs);
getContext().getContentResolver().notifyChange(uri, null);
return rows;
}
}
Table.java
public class Table {
private static final Uri URI = Uri.parse("content://info.justoneplanet.android.sample.provider/");
private Context mContext;
public Table(Context context) {
mContext = context;
}
/**
* データを取得する
* @return ListActivity用のadapter
*/
public void load(final LoadObserver observer)
{
AsyncQueryHandler handler = new AsyncQueryHandler(mContext.getContentResolver()) {
@Override
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
super.onQueryComplete(token, cookie, cursor);
observer.onLoadCursor(cursor);
}
};
handler.startQuery(0, null, URI, null, null, null, Helper.CREATED + " DESC");
}
/**
* 保存する
* @return
*/
public void add(String name) {
ContentValues contentValues = new ContentValues();
contentValues.put(Helper.NAME, name);
contentValues.put(Helper.CREATED, new Date().getTime());
AsyncQueryHandler handler = new AsyncQueryHandler(mContext.getContentResolver()) {
@Override
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
super.onQueryComplete(token, cookie, cursor);
}
};
handler.startInsert(0, null, URI, contentValues);
}
/**
* 一定時間経過したものを削除する
* @param created
* @return
*/
public void delete(long created) {
AsyncQueryHandler handler = new AsyncQueryHandler(mContext.getContentResolver()) {
};
handler.startDelete(0, null, URI, Helper.CREATED + " < ?", new String[]{String.valueOf(created)});
}
/**
* helper経由でdbをcloseする
*/
public void close() {
Helper.getInstance(mContext, null).close();
}
public interface LoadObserver {
public void onLoadCursor(Cursor cursor);
}
}
悪い例
以下のようにAsyncQueryHandlerのサブクラスを作った。
private class SQLAsyncQueryHandler extends AsyncQueryHandler {
public SQLAsyncQueryHandler(ContentResolver cr) {
super(cr);
}
@Override
public void startQuery(int token, Object cookie, Uri uri, String[] projection, String selection, String[] selectionArgs, String orderBy) {
SQLiteDatabase sdb = getWritableDatabase();
Cursor cursor = sdb.query(
"tbl",
projection,
selection,
selectionArgs,
null,
null,
orderBy,
null
);
}
@Override
protected void onQueryComplete (int token, Object cookie, Cursor cursor) {
Log.e("cursor", cursor.toString());
}
}
クライアントコード
以下のように使用する。
SQLAsyncQueryHandler handler = new SQLAsyncQueryHandler(mContext.getContentResolver());
handler.startQuery(0, null, null, null, null, null, null);