SQLiteOpenHelperのonCreate,onUpgradeメソッド内でSQLiteDatabaseオブジェクトをcloseすると、IllegalStateException: database not open の例外で落ちることがあります。
SQLiteOpenHelperを継承したIllegalStateExceptionの例
package com.luckyandhappy;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class SampleDatabaseHelper extends SQLiteOpenHelper {
private static final String TAG = SampleDatabaseHelper.class.getSimpleName();
private static final String DB_NAME = "Sample.db";
private static final int DB_VERSION = 1;
public SampleDatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.beginTransaction();
try {
db.execSQL("CREATE TABLE `persons` (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)");
}
catch(Exception e) {
Log.e(TAG,"スキーマ作成中に例外が発生しました",e);
db.setTransactionSuccessful();
}
finally {
db.endTransaction();
///// !!!!! /////
///// ここでcloseするとSQLiteDatabaseオブジェクトの状態が
///// 変わって他のメソッドに影響します!
db.close();
}
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
public List<Person> findAllPersons() {
List<Person> persons = new ArrayList();
SQLiteDatabase db = getWritableDatabase();
Cursor cursor = db.query("persons", new String[]{"id","name"}, null, null, null, null, null);
while(cursor.moveToNext()) {
Person person = new Person();
person.setId(cursor.getInt(0));
person.setName(cursor.getString(1));
persons.add(person);
}
db.close();
return persons;
}
public void save(Person person) {
SQLiteDatabase db = getWritableDatabase();
db.beginTransaction();
try {
db.execSQL("INSERT INTO `persons` (name) VALUES (?)", new String[]{person.getName()});
db.setTransactionSuccessful();
} catch (Exception e) {
Log.e(TAG, "保存中に例外が発生しました",e);
} finally {
db.endTransaction();
db.close();
}
}
public void deleteAllPersons() {
SQLiteDatabase db = getWritableDatabase();
db.beginTransaction();
try {
db.execSQL("DELETE FROM `persons`");
db.setTransactionSuccessful();
} catch (Exception e) {
Log.e(TAG, "削除中に例外が発生しました",e);
} finally {
db.endTransaction();
db.close();
}
}
}
例外
Caused by: java.lang.IllegalStateException: database not open at android.database.sqlite.SQLiteDatabase.endTransaction(SQLiteDatabase.java:555) at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:137) at com.luckyandhappy.SampleDatabaseHelper.deleteAllPersons(SampleDatabaseHelper.java:74) at com.luckyandhappy.SQLiteOnCreateExampleActivity.onCreate(SQLiteOnCreateExampleActivity.java:18) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611) ... 11 more
データベースが存在しない場合に、一番最初のsave、deleteAllPersons, findAllPersons内でgetWritabeDatabaseが呼ばれると、onCreateが呼ばれます。一連のOpen-Closeの中でonCreateが実行されますので、勝手にSQLiteOpenHelperをcloseすると後のクエリが正しく実行されません。
なのでonCreateを以下のように修正します。
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE `persons` (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)");
}
同様の理由で、どこかでopenしたまま、closeして、更にクエリを流すとこのIlligalStateExceptionが発生します。Open/Closeをイチイチ記述するのがベターです。SQLiteDatabaseオブジェクトのisOpenメソッドでチェックしてからgetWritableDatabaseを使うともう少し良いかもです。
わかれば簡単ですが地味にハマります。
0 件のコメント:
コメントを投稿