Android Error处理:java.lang.IllegalStateException: databases already closed
今天导入一个基于Android 2.x版本SDK项目,运行的时候一直出错,错误如下:
11-18 16:58:56.595:E/AndroidRuntime(22991): java.lang.RuntimeException: Unable to start servicexxx.xxxx.service.LocalService@41985638 with Intent {act=xxx.xxx.xxx.APP_SERVICE (has extras) }: java.lang.IllegalStateException:database /data/data/xxx.xxx.xxx/databases/xxx.db (conn# 0) already closed
package org.yousee.utils; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteDatabase.CursorFactory; /** * 存储记录的数据库 */ public class DBHelper extends SQLiteOpenHelper { private Cursor c = null; private static final String CREATE_TAB = "create table " + "music(_id integer primary key autoincrement,music_id integer,clicks integer," + "latest text)"; private static final String TAB_NAME = "list"; private SQLiteDatabase db = null; public DBHelper(Context context, String name, CursorFactory factory,int version) { super(context, name, factory, version); } @Override public void onCreate(SQLiteDatabase db) { this.db = db; db.execSQL(CREATE_TAB); } public void insert(ContentValues values){ SQLiteDatabase db = this.getWritableDatabase(); db.insert(TAB_NAME, null, values); db.close();//应改为this.close() } public void update(ContentValues values,int id){ SQLiteDatabase db = this.getWritableDatabase(); db.update(TAB_NAME, values, "music_id="+id, null); db.close();//应改为this.close() } public void delete(int id){ if (db == null){ db = getWritableDatabase(); } db.delete(TAB_NAME, "music_id=?", new String[]{String.valueOf(id)}); } public Cursor query(int id){ SQLiteDatabase db = getReadableDatabase(); c = db.query(TAB_NAME, null, "music_id=?", new String[]{String.valueOf(id)}, null, null, null); db.close();//应改为this.close() return c; } public Cursor queryByClicks(){//按点击量查询 SQLiteDatabase db = getReadableDatabase(); c = db.query(TAB_NAME, null, null, null, null, null, "clicks desc"); return c; } public Cursor queryRecently(){//按时间降序查询 SQLiteDatabase db = getReadableDatabase(); c = db.query(TAB_NAME, null, null, null, null, null, "latest desc"); return c; } public void close(){ if (db != null){ db.close();//应改为this.close() db=null; } if (c!=null){ c.close(); c=null; } } @Override public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) { } }经过 分析发现是关闭数据库时直接调用了SQLiteDatabase.close()方法。
出错的具体原因为:
如果调用SQLiteDatabase.close()代替SQLiteOpenHelper.close()。那么SQLiteOpenHelper就不知道通过helper获取的DB是否是关闭的(getReadableDatabase或getWritableDatabase)。
总结:
1、SQLiteOpenHelper.close()是异步的,而SQLiteDatabase.close()不是。
2、在使用安卓提供的SQLiteOpenHelper时,通过getReadableDatabase或getWritableDatabase获得的其实是同一个对象,唯一的却别就是如果你的硬盘不足了,那么你就不能在调用getWritableDatabase,只能调用getReadableDatabase。
3、使用Android提供的数据库接口进行数据库操作的时候一定要遵循Andoid的规则。在多线程中要注意,所以养成好的面向对象的习惯,调用helper的close方法关闭数据库。(谁提供的数据,就调用谁的方法来操作数据)
网上还看到有类似的问题:
http://androiddev.orkitra.com/?p=30756
http://stackoverflow.com/questions/6535908/android-sqlite-sqliteopenhelper-error-illegalstateexception-db-already-clo