intentで撮影した写真のURIをデータベースに記録する簡単な実験をやってみた。今回はGUIや表示などは置いておいて、とりあえずAndroidアプリ内でデータベースを取扱うのに慣れることを目標とする。
データベースを開く方法は複数
Androidではsqliteデータベースが標準でサポートされてはいるが、具体的なやり方にはいくつかバリエーションがある。データベースを開く方法1つとっても下記3種類もあってどれを使っていいか悩む。
- SQLiteOpenHelper
- SQLiteDatabase#openOrCreateDatabase
- Context#openOrCreateDatabase
SQLiteOpenHelperを使うとデータベースの新規作成の処理などを自動化出来るので便利なのだが、データベースファイルの存在が隠蔽されすぎていて、今回のアプリで掲げた「Linux Boxでデータベースファイルを作成する」という方針に合わないためパス。というわけで2. 3. のいずれかの方法になるのだが、SQLiteDatabase#openOrCreateDatabaseはデータベースファイルのパーミッションが設定できなくて問題がありそう。というわけで、今回はContext#openOrCreateDatabaseを使うことにする。
別モジュールを作成するときのオマジナイ
今回、データベースを取り扱う一連の処理をまとめたDBAdapterクラスを別モジュールとして定義した。
このとき、モジュールの先頭に、
package com.example.photologger;
などとパッケージ名書いておくと、コンパイラが勝手にモジュール間参照を行ってくれる。CとかC++だとモジュール間参照のためにヘッダファイル(.h)を作って、参照元でそれをインクルードする必要があって結構面倒くさいのだが、javaの世界は便利な仕組みがあって良い。
DBAdapterクラスの定義
とりあえずは、テーブル作成と簡単なレコードの読み書きだけを実装した。
コンストラクタでテーブルの存在確認のため、SELECT文のSQLを実行しgetCountでチェックを行っているのがポイント。無ければテーブルを作成するSQLを実行。
savePhotoURIメソッドが呼ばれると、URIを文字列に変換してテーブルに挿入。
checkRecordメソッドはテーブルの内容をログにダンプする。
public class LogDBAdapter {
private static final String LOG_TAG = "PhotoLogger";
private static final String DATABASE_NAME = "photolog.db";
private static final String PHOTO_TABLE_NAME = "photolog";
private static final String COL_ID = "id";
private static final String COL_PHOTO_URI = "photo_uri";
private static final String PHOTO_TABLE_CREATE =
"CREATE TABLE " + PHOTO_TABLE_NAME + " (" +
COL_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
COL_PHOTO_URI + " TEXT);";
private static Context context;
SQLiteDatabase db;
LogDBAdapter(Context con) {
context = con;
try {
db = context.openOrCreateDatabase(DATABASE_NAME, Context.MODE_PRIVATE, null);
// テーブルの存在確認
final String query = "SELECT name FROM sqlite_master WHERE type='table' AND name='" + PHOTO_TABLE_NAME + "';";
Cursor c = db.rawQuery(query, null);
int cnt = c.getCount();
c.close();
if ( cnt == 0 ) {
// テーブルが無い時→新規作成
db.execSQL(PHOTO_TABLE_CREATE);
}
} catch(SQLiteException err){
Log.e(LOG_TAG, err.getMessage());
}
}
void savePhotoURI(Uri uri) {
String strURI = uri.toString();
String sql = "insert into " + PHOTO_TABLE_NAME + "(" + COL_PHOTO_URI + ") values('" + strURI + "');";
Cursor c = null;
try {
db.execSQL(sql);
} catch(SQLiteException err){
Log.e(LOG_TAG, err.getMessage());
} finally {
if ( c != null ) {
c.close();
}
}
}
void checkRecord() {
final String query = "SELECT " + COL_ID + "," + COL_PHOTO_URI + " FROM " + PHOTO_TABLE_NAME + ";";
Cursor c = null;
try {
c = db.rawQuery(query, null);
c.moveToFirst();
while ( !c.isAfterLast() ) {
String id = c.getString(0);
String uri = c.getString(1);
Log.i(LOG_TAG, "id:" + id + ",uri:" + uri);
c.moveToNext();
}
} catch(SQLiteException err){
Log.e(LOG_TAG, err.getMessage());
} finally {
if ( c != null ) {
c.close();
}
}
}
}
MainActivity.javaへコード追加
MainActivity.javaにいくつかコードを追加。以下、抜粋。
public class MainActivity extends AppCompatActivity {
static final int REQUEST_IMAGE_CAPTURE = 1;
static LogDBAdapter dba; // DBアダプタ
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
dba = new LogDBAdapter(this); // DBアダブタの生成
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
Uri uri = data.getData();
dba.savePhotoURI(uri); // DBレコードの追加
} else {
// キャンセルした時など
Log.i("PhotoLogger","Failed to take photo.");
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
dba.checkRecord(); // Settingメニューを選んだ時に実行
return true;
}
return super.onOptionsItemSelected(item);
}
:
(略)
}
カメラ起動intentのハンドラでsavePhotoURIを呼んで撮った写真のURIを記録している。そして、メニューを選択したときにcheckRecordメソッドを呼んでテーブルの中身をログ吐き出す。吐き出されたログは以下。
06-01 13:37:53.371 20003-20003/com.example.photologger I/PhotoLogger: id:1,uri:content://media/external/images/media/260
06-01 13:37:53.371 20003-20003/com.example.photologger I/PhotoLogger: id:2,uri:content://media/external/images/media/261
06-01 13:37:53.371 20003-20003/com.example.photologger I/PhotoLogger: id:3,uri:content://media/external/images/media/262
06-01 13:37:53.371 20003-20003/com.example.photologger I/PhotoLogger: id:4,uri:content://media/external/images/media/263
コメント