Androidアプリでsqliteデータベースを操作する

intentで撮影した写真のURIをデータベースに記録する簡単な実験をやってみた。今回はGUIや表示などは置いておいて、とりあえずAndroidアプリ内でデータベースを取扱うのに慣れることを目標とする。

スポンサーリンク

データベースを開く方法は複数

Androidではsqliteデータベースが標準でサポートされてはいるが、具体的なやり方にはいくつかバリエーションがある。データベースを開く方法1つとっても下記3種類もあってどれを使っていいか悩む。

  1. SQLiteOpenHelper
  2. SQLiteDatabase#openOrCreateDatabase
  3. 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

コメント