@blog.justoneplanet.info

日々勉強

AndroidでCursorLoaderを使ってみる

以下のようにしてCursorLoaderを使用する。

public class MainFragment extends ListFragment
    implements LoaderManager.LoaderCallbacks<Cursor> {
    private ListView mListView;

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        mListView = getListView();
        mListView.setCacheColorHint(0);
        mAdapter = new EmoticonSimpleCursorAdapter(
                getActivity().getApplicationContext(),
                R.layout.list,
                null,
                new String[]{Table.TITLE, Table.CONTENT},
                new int[]{R.id.list_title, R.id.list_content},
                this
        );
        setListAdapter(mAdapter);
        super.onViewCreated(view, savedInstanceState);
    }
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        getLoaderManager().initLoader(0, null, this);
    }
    @Override
    public void onDestroyView() {
        super.onDestroyView();
        getLoaderManager().destroyLoader(0);
    }
    private void reload() {
        getLoaderManager().restartLoader(0, null, this);
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        return new CursorLoader(getActivity().getApplicationContext(), Provider.URI, null, null, null, Table.CREATED + " DESC");
    }
    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        mAdapter.swapCursor(data);
    }
    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        mAdapter.swapCursor(null);
    }
}

ContentProviderを使ってSQLiteに複数行Insertする

■ContentProvider

以下のようにbulkInsertメソッドをOverrideする。

public class Provider extends ContentProvider {
    public static final Uri URI = Uri.parse("content://com.example.android.hoge/");
    @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(
                Table.TABLENAME,
                new String[]{Table.ID, Table.DATA, Table.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(Table.TABLENAME, null, values);
        getContext().getContentResolver().notifyChange(uri, null);
        return uri;
    }
    
    /**
     * superクラスでinsertを普通に呼ぶようなのでcompileStatementの処理を自前で書く
     */
    @Override
    public int bulkInsert(Uri uri, ContentValues[] values) {
        Helper helper = Helper.getInstance(getContext(), null);
        SQLiteDatabase sdb = helper.getWritableDatabase();
        
        sdb.beginTransaction();
        SQLiteStatement stmt = sdb.compileStatement(
            "INSERT INTO `" + Table.TABLENAME + "`(`" + Table.DATA + "`, `" + Table.CREATED + "`) VALUES (?, ?);"
        );
        int length = values.length;
        for(int i = 0; i < length; i++){
            stmt.bindString(1, values[i].getAsString(Table.DATA));
            stmt.bindLong(2, values[i].getAsLong(Table.CREATED));
            stmt.executeInsert();
        }
        sdb.setTransactionSuccessful();
        sdb.endTransaction();
        return length;
    }
    
    @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(Table.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(Table.TABLENAME, selection, selectionArgs);
        getContext().getContentResolver().notifyChange(uri, null);
        return rows;
    }
    
    private static class Helper extends SQLiteOpenHelper {
        static Helper INSTANCE = null;
        private Helper(Context context, CursorFactory factory) {
            super(context, Table.FILENAME, factory, Table.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 `" + Table.TABLENAME + "`(" +
                " `" + Table.ID      + "` INTEGER PRIMARY KEY AUTOINCREMENT," +
                " `" + Table.CREATED + "` INTEGER," +
                " `" + Table.DATA    + "` TEXT" +
                ");"
            );
        }
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        }
    }
}

super.bulkInsert(uri, values)は内部でinsert(uri, values)を複数回呼び出すようになっており、Insert文が複数回発行されて非常に遅くなる。

■クライアントコード

ContentValues[] contentValues = new ContentValues[length];
for(int i = 0; i < length; i++){
    ContentValues values = new ContentValues();
    values.put(DATA, "data_" + i);
    values.put(CREATED, new Date().getTime());
    contentValues[i] = values;
}
getApplicationContext().getContentResolver().bulkInsert(Provider.URI, contentValues);

nodeでHMAC-MD5を計算する

JavaやObjective-Cと違って1行で記述できる。

var crypto = require('crypto');
crypto.createHmac('md5', 'key').update(str).digest('hex');

md5値を求める場合は以下のようにする。

var crypto = require('crypto');
crypto.createHash('md5').update(str).digest('hex');

参考