SQLiteDatabase
メシ作成後に掘削してみた記録。
先日、ContentResolver 使う方式で書き換えた Notepad の SQLiteDatabase#query 呼び出す箇所が以下。
@Override public Cursor query( Uri url, String[] projection, String selection, String[] selectionArgs, String sort) { Cursor c = db.query(true, NotesColumns.NOTES_TABLE, new String[] {NotesColumns._ID, NotesColumns.KEY_TITLE, NotesColumns.KEY_BODY}, selection, null, null, null, null, null); c.setNotificationUri(getContext().getContentResolver(), url); return c; }
SQLiteDatabase の実装を見てみるか、という事で frameworks/base/core/java/android/database/sqlite/SQLiteDatabase.java の中身を確認。query メソドの定義は以下。
public Cursor query(boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) { return queryWithFactory(null, distinct, table, columns, selection, selectionArgs, groupBy, having, orderBy, limit); }
queryWithFactory は以下。
public Cursor queryWithFactory(CursorFactory cursorFactory, boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) { String sql = SQLiteQueryBuilder.buildQueryString( distinct, table, columns, selection, groupBy, having, orderBy, limit); return rawQueryWithFactory( cursorFactory, sql, selectionArgs, findEditTable(table)); }
ええと、rowQueryWithFactory メソドは以下か。
public Cursor rawQueryWithFactory( CursorFactory cursorFactory, String sql, String[] selectionArgs, String editTable) { long timeStart = 0; if (Config.LOGV) { timeStart = System.currentTimeMillis(); } SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable); try { return driver.query( cursorFactory != null ? cursorFactory : mFactory, selectionArgs); } finally { if (Config.LOGV) { long duration = System.currentTimeMillis() - timeStart; Log.v(SQLiteCursor.TAG, "query (" + duration + " ms): " + driver.toString() + ", args are " + (selectionArgs != null ? TextUtils.join(",", selectionArgs) : "<null>")); } } }
ええと、SQLiteDirectCursorDriver クラスのオブジェクトをナニして query メソドを呼び出しております。SQLiteDirectCursorDriver.java は同じディレクトリにある模様。query メソドが以下か。
public Cursor query(CursorFactory factory, String[] selectionArgs) { // Compile the query SQLiteQuery query = new SQLiteQuery(mDatabase, mSql, 0, selectionArgs); try { // Arg binding int numArgs = selectionArgs == null ? 0 : selectionArgs.length; for (int i = 0; i < numArgs; i++) { query.bindString(i + 1, selectionArgs[i]); } // Create the cursor if (factory == null) { mCursor = new SQLiteCursor(mDatabase, this, mEditTable, query); } else { mCursor = factory.newCursor(mDatabase, this, mEditTable, query); } mQuery = query; query = null; return mCursor; } finally { // Make sure this object is cleaned up if something happens if (query != null) query.close(); } }
ここで SQLiteCursor が出てきます。ちなみに query の引数 factory は SQLiteDatabase から延々と渡されているもので rawQueryWithFactory メソドで
return driver.query( cursorFactory != null ? cursorFactory : mFactory, selectionArgs);
なカンジのナニがあります。cursorFactory は null のはずなので mFactory が渡されるはずなんですが、mFactory 属性はコンストラクタで設定されてます。
private SQLiteDatabase(String path, CursorFactory factory, int flags) { if (path == null) { throw new IllegalArgumentException("path should not be null"); } mFlags = flags; mPath = path; mLogStats = "1".equals(android.os.SystemProperties.get("db.logstats")); mLeakedException = new IllegalStateException(path + " SQLiteDatabase created and never closed"); mFactory = factory;
あら? コンストラクタが private だな。コメントによれば create と openDatabase を見れ、とある模様。create メソドの定義が以下。
public static SQLiteDatabase create(CursorFactory factory) { // This is a magic string with special meaning for SQLite. return openDatabase(":memory:", factory, CREATE_IF_NECESSARY); }
openDatabase を呼び出してますな。openDatabase メソドの定義が以下。
public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags) { SQLiteDatabase db = null; try { // Open the database. return new SQLiteDatabase(path, factory, flags); } catch (SQLiteDatabaseCorruptException e) { // Try to recover from this, if we can. // TODO: should we do this for other open failures? Log.e(TAG, "Deleting and re-creating corrupt database " + path, e); new File(path).delete(); return new SQLiteDatabase(path, factory, flags); } }
うーん。Notepad を再確認してみたところ、SQLiteDatabase なオブジェクトは
DatabaseHelper dbHelper = new DatabaseHelper(getContext()); db = dbHelper.getWritableDatabase();
という方法で取得しておる模様。DatabaseHelper って何だ。って内部定義なソレですた。
private static class DatabaseHelper extends SQLiteOpenHelper {
って事は SQLiteOpenHelper 見てみれば良いのか。frameworks/base/core/java/android/database/sqlite/SQLiteOpenHelper.java なんですが、特に factory 云々は気にしないことにしよ。
結局
SQLiteCursor に戻ってきました。明日以降ここにフォーカスして頑張ります。