【Android】特定のDatabaseファイルを簡単に削除する


AndroidでSQLiteを使っている場合、時々テーブルの削除(Drop Table)ではなく、Databasesファイル自体を削除したい時がある。
そういった場合android.content.ContextクラスのdeleteDatabaseメソッドを使えば、特定のDatabasesファイルを簡単に削除できます。

Context#deleteDatabaseメソッド

使い方はとても簡単。

// context=Context helper=SQLiteOpenHelper
context.deleteDatabase(helper.getDatabaseName());

引数に削除したいDatabasesファイルのファイル名を渡すだけで削除できます。
※戻り値がbooleanなので、適切に処理する場合は戻り値を確認する
※Databaseファイルをアプリケーションディレクトリの/databasesディレクトリ以外に作成している場合は例外

しかし、このメソッドではDatabaseファイルのjournalファイルが削除対象に含まれていないという問題があります。
※Databasesファイルに関連する全ファイルが削除できていないことを問題視してます

実際にソースを確認してみると、以下のようにjournalファイルは削除対象に含まれていません。
※Android 4.0.4のContextImplクラスの実装
http://tools.oesf.biz/android-4.0.4_r1.0/xref/frameworks/base/core/java/android/app/ContextImpl.java#775

@Override
public boolean deleteDatabase(String name) {
    try {
        File f = validateFilePath(name, false); // DatabaseファイルのObjectを生成
        return f.delete();
    } catch (Exception e) {
    }
    return false;
}

そこで、この問題を解決するためのメソッドが次に説明するものです。

SQLiteDatabase#deleteDatabaseメソッド

API Level 16(Android 4.1-Jelly Bean)からandroid.database.sqlite.SQLiteDatabaseクラスのdeleteDatabaseメソッドが追加されています。
このメソッドは、上記のContext#deleteDatabaseメソッドと同様に指定したDatabasesファイルを削除するメソッドです。
※ちなみに、こちらはstaticメソッドです

Context#deleteDatabaseメソッドと違う点は、以下のようなことです。

  • journalファイルも削除対象に含まれている
  • WAL(Write Ahead Logging)関連のファイル(-shm,-wal)も削除対象に含まれている
  • アプリケーションディレクトリのdatabases配下以外に作成したDatabasesファイルも削除できる(引数がFileオブジェクトのため)

使い方はとても簡単です。

// context=Context helper=SQLiteOpenHelper
SQLiteDatabase.deleteDatabase(context.getDatabasePath(helper.getDatabaseName()));

/databases配下にあるDatabasesファイルを削除したい場合、引数にFileオブジェクトを渡さないといけないので
ContextクラスのgetDatabasePathメソッドで削除したいDatabasesファイルのFileオブジェクトを生成して渡します。

ちなみに、API Level 16以降はContext#getDatabasePathメソッドも内部的にSQLiteDatabase#deleteDatabaseメソッドを使用しています。
※Android 4.1.1のContextImplクラスの実装
http://tools.oesf.biz/android-4.1.1_r1.0/xref/frameworks/base/core/java/android/app/ContextImpl.java#809

@Override
public boolean deleteDatabase(String name) {
    try {
        File f = validateFilePath(name, false);
        return SQLiteDatabase.deleteDatabase(f);
    } catch (Exception e) {
    }
    return false;
}

なので、API Level 16以降はContext#deleteDatabaseメソッドを使った場合、SQLiteDatabase#deleteDatabaseメソッドを使用したのと同じことになります。
ナイスな実装になってますね!

まとめ

あーAPI Level 16からのメソッドかー。
という落ち込み具合がやばいですが、このメソッド別にAPI Level 16に依存したメソッド等を使用してないので、実はSDKの実装をコピペできます。
なぜAPI Level 1 からないんだよーと言いたくなるメソッドなので、API Level 16以下でこのメソッドが欲しくなったらSDKの実装をコピペしてください!
※よくない方法ですが、まあ仕方ない…

余談ですが、今回紹介したメソッドの実装を見ているとdatabases配下に作成したDatabasesファイルを全て作成する!みたいな実装も簡単にできることがわかります。
コードリーティングは大事です!