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
判断可能是数据库操作部分出了问题,数据库操作部分文件代码DBHelper.java如下:
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