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 件のコメント:
コメントを投稿