我写了一个sqldb帮助程序类来处理一些我希望在本地保存的webservice信息相关数据我在使用后保持所有sqlite引用关闭但是我仍然得到“java.lang.IllegalStateException:尝试重新打开已经 - 封闭对象“一旦调用”AddNonceForMethod“方法,这里是我的代码 -
public class WebServicesDataManager extends SQLiteOpenHelper {
/* Class Variables */
private final String TAG = WebServicesDataManager.class.getSimpleName();
// Database Version
private static final int DATABASE_VERSION = 1;
// Database Name
public static final String DATABASE_NAME = "dmx";
// Tables
private static final String TABLE_WEBSERVICES = "webservices";
private static final String TABLE_COOKIE = "cookie";
private static final String TABLE_INFORMATION = "information";
// Tables and table columns names
private String CREATE_WEBSERVICES_TABLE;
private static final String COLUMN_METHOD_ID = "method_id";
private static final String COLUMN_METHOD_NAME = "method_name";
private static final String COLUMN_METHOD_NONCE = "method_nonce";
private static final String COLUMN_METHOD_NONCE_TIME_STAMP = "nonce_time_stamp";
private static final String COLUMN_USER_COOKIE = "user_cookie";
private String CREATE_COOKIE_TABLE;
private static final String COLUMN_COOKIE_STRING = "cookie_string";
private static final String COLUMN_COOKIE_TIME_STAMP = "cookie_time_stamp";
private String CREATE_INFORMATION_TABLE;
private static final String COLUMN_INFORMATION_ID = "info_id";
private static final String COLUMN_INFO_VERSION_NUMBER = "info_version_number";
/**
* Class constructor
*
* @param context
* The context to run in
*/
public WebServicesDataManager(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
// Creating Tables
@Override
public void onCreate(SQLiteDatabase db) {
CREATE_WEBSERVICES_TABLE = "CREATE TABLE IF NOT EXISTS "
+ TABLE_WEBSERVICES + " (" + COLUMN_METHOD_ID
+ " INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "
+ COLUMN_METHOD_NAME + " VARCHAR(64) NOT NULL, "
+ COLUMN_METHOD_NONCE + " VARCHAR(64) NULL, "
+ COLUMN_METHOD_NONCE_TIME_STAMP + " VARCHAR(64) NULL, "
+ COLUMN_USER_COOKIE + " VARCHAR(64) NULL);";
CREATE_COOKIE_TABLE = "CREATE TABLE IF NOT EXISTS " + TABLE_COOKIE
+ " (" + COLUMN_COOKIE_STRING + " VARCHAR(64) NULL, "
+ COLUMN_COOKIE_TIME_STAMP + " VARCHAR(64) NOT NULL);";
CREATE_INFORMATION_TABLE = "CREATE TABLE IF NOT EXISTS "
+ TABLE_INFORMATION + " (" + COLUMN_INFORMATION_ID
+ " INTEGER NOT NULL, " + COLUMN_INFO_VERSION_NUMBER
+ " VARCHAR(64) NOT NULL" + ");";
// create the tables
db.execSQL(CREATE_WEBSERVICES_TABLE);
db.execSQL(CREATE_COOKIE_TABLE);
db.execSQL(CREATE_INFORMATION_TABLE);
}
// Upgrading database
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Drop older table if existed
db.execSQL("DROP TABLE IF EXISTS " + TABLE_WEBSERVICES);
db.execSQL("DROP TABLE IF EXISTS " + TABLE_COOKIE);
db.execSQL("DROP TABLE IF EXISTS " + TABLE_INFORMATION);
// Create tables again
onCreate(db);
}
/**
* Adds a nonce value for an exisiting method in the database or create a
* new method and add a nonce for it
*
* @param method
* A mtehod defined on the Method enum
* @param nonce
* The nonce value to add for the method
* @return True if the process succeed false otherwise
*/
public boolean AddNonceForMethod(Method method, String nonce) {
// method variables
String now = null;
String methodTimeStamp;
boolean pass = true;
SQLiteDatabase db = null;
ContentValues values = null;
long hours = 20l;
long rowsAffected;
// try to add a nonce for a method
try {
if (nonce != null) {
String oldNonce = GetNonceForMethod(method);
if (!nonce.equals(oldNonce)) {
RemoveNonceForMethod(method);
db = this.getWritableDatabase();
now = getDateTime();
values = new ContentValues();
values.put(COLUMN_METHOD_NAME, method.name());
values.put(COLUMN_METHOD_NONCE, nonce);
values.put(COLUMN_METHOD_NONCE_TIME_STAMP, now);
rowsAffected = db.insert(TABLE_WEBSERVICES, null, values);
if (rowsAffected == -1) {
pass = false;
}
}
}
} catch (SQLException exception) {
Log.e(TAG, exception.getMessage());
pass = false;
} finally {
if (db != null) {
// close database connection
db.close();
db = null;
}
}
return pass;
}
/**
* Gets a cookie from the databse in case there is one else, return NAN in
* case of failure return null
*
* @return The cookie as string format
*/
public String GetNonceForMethod(Method method) {
// method variables
int columnTimeStampIndex = -1;
int columnNonceIndex = -1;
String nonce = null;
String timeStamp = Constants.NAN;
SQLiteDatabase db = null;
String now = null;
long hours = 48l;
Cursor cursor = null;
// try to get the method id from the database
try {
db = this.getReadableDatabase();
cursor = db.query(TABLE_WEBSERVICES, new String[] {
COLUMN_METHOD_NAME, COLUMN_METHOD_NONCE,
COLUMN_METHOD_NONCE_TIME_STAMP }, COLUMN_METHOD_NAME
+ " = ?", new String[] { method.name() }, null, null, null);
if (cursor != null) {
boolean moved = cursor.moveToFirst();
if (moved) {
columnNonceIndex = cursor
.getColumnIndex(COLUMN_METHOD_NONCE);
columnTimeStampIndex = cursor
.getColumnIndex(COLUMN_METHOD_NONCE_TIME_STAMP);
if (columnTimeStampIndex > -1) {
timeStamp = cursor.getString(columnTimeStampIndex);
now = getDateTime();
if (timeStamp != null && timeStamp != Constants.NAN
&& isTimeDiffLower(timeStamp, now, hours)) {
nonce = cursor.getString(columnNonceIndex);
}
}
}
}
} catch (SQLException exception) {
nonce = null;
Log.e(TAG, exception.getMessage());
} finally {
if (cursor != null) {
// close cursor stream
cursor.close();
}
if (db != null) {
// close database connection
db.close();
db = null;
}
}
return nonce;
}
private boolean RemoveNonceForMethod(Method method) {
// method variables
boolean pass = true;
SQLiteDatabase db = null;
long rowsAffected = 0;
// try to add a nonce for a method
try {
db = this.getWritableDatabase();
rowsAffected = db.delete(TABLE_WEBSERVICES, COLUMN_METHOD_NAME
+ "=?", new String[] { method.name() });
if (rowsAffected == 0) {
pass = false;
}
} catch (SQLException exception) {
Log.e(TAG, exception.getMessage());
pass = false;
} finally {
if (db != null) {
// close database connection
db.close();
db = null;
}
}
return pass;
}
/**
* Add a new cookie for the database
*
* @param cookie
* The cookie to add
* @param timeStamp
* The cookie time stamp
* @return True if the process succeed false otherwise
*/
public boolean AddCookie(String cookie) {
// method variables
long rowId;
boolean pass = false;
SQLiteDatabase db = null;
ContentValues row = null;
// try to add the cookie to the db
try {
row = new ContentValues();
db = this.getWritableDatabase();
row.put(COLUMN_COOKIE_STRING, cookie);
row.put(COLUMN_COOKIE_TIME_STAMP, getDateTime());
rowId = db.insert(TABLE_COOKIE, null, row);
if (rowId > -1) {
pass = true;
}
} catch (SQLException exception) {
Log.e(TAG, exception.getMessage());
} finally {
if (db != null) {
// close database connection
db.close();
}
}
return pass;
}
/**
* Gets a cookie from the databse in case there is one else, return NAN in
* case of failure return null
*
* @return The cookie as string format
*/
public String GetCookie() {
// method variables
int columnIndex = -1;
String cookie = Constants.NAN;
SQLiteDatabase db = null;
Cursor cursor = null;
// try to get the method id from the database
try {
db = this.getReadableDatabase();
cursor = db.query(TABLE_COOKIE, null, null, null, null, null, null);
if (cursor != null) {
boolean moved = cursor.moveToFirst();
if (moved) {
columnIndex = cursor.getColumnIndex(COLUMN_COOKIE_STRING);
if (columnIndex > -1) {
cookie = cursor.getString(columnIndex);
}
}
}
} catch (SQLException exception) {
cookie = null;
Log.e(TAG, exception.getMessage());
} finally {
if (cursor != null) {
// close cursor stream
cursor.close();
}
if (db != null) {
// close database connection
db.close();
}
}
return cookie;
}
}
和logcat输出 -
04-18 21:15:24.971: E/AndroidRuntime(28060): FATAL EXCEPTION: main
04-18 21:15:24.971: E/AndroidRuntime(28060): java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /data/data/com.tmc/databases/tmc
04-18 21:15:24.971: E/AndroidRuntime(28060): at android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:55)
04-18 21:15:24.971: E/AndroidRuntime(28060): at android.database.sqlite.SQLiteDatabase.delete(SQLiteDatabase.java:1614)
04-18 21:15:24.971: E/AndroidRuntime(28060): at com.tmc.logic.db.WebServicesDataManager.RemoveNonceForMethod(WebServicesDataManager.java:229)
04-18 21:15:24.971: E/AndroidRuntime(28060): at com.tmc.logic.db.WebServicesDataManager.AddNonceForMethod(WebServicesDataManager.java:134)
04-18 21:15:24.971: E/AndroidRuntime(28060): at com.tmc.ActivityDebug$1.onClick(ActivityDebug.java:43)
04-18 21:15:24.971: E/AndroidRuntime(28060): at android.view.View.performClick(View.java:4475)
04-18 21:15:24.971: E/AndroidRuntime(28060): at android.view.View$PerformClick.run(View.java:18786)
04-18 21:15:24.971: E/AndroidRuntime(28060): at android.os.Handler.handleCallback(Handler.java:730)
04-18 21:15:24.971: E/AndroidRuntime(28060): at android.os.Handler.dispatchMessage(Handler.java:92)
04-18 21:15:24.971: E/AndroidRuntime(28060): at android.os.Looper.loop(Looper.java:137)
04-18 21:15:24.971: E/AndroidRuntime(28060): at android.app.ActivityThread.main(ActivityThread.java:5419)
04-18 21:15:24.971: E/AndroidRuntime(28060): at java.lang.reflect.Method.invokeNative(Native Method)
04-18 21:15:24.971: E/AndroidRuntime(28060): at java.lang.reflect.Method.invoke(Method.java:525)
04-18 21:15:24.971: E/AndroidRuntime(28060): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1187)
04-18 21:15:24.971: E/AndroidRuntime(28060): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
04-18 21:15:24.971: E/AndroidRuntime(28060): at dalvik.system.NativeStart.main(Native Method)
任何帮助???
答案 0 :(得分:3)
在方法AddNonceForMethod()
中看到你正在调用另一个方法RemoveNonceForMethod()
,这就是你得到异常的地方(如果你仔细查看你的logcat你会得到的),现在又回到例外: -
您正在使用this.getWritableDatabase()
创建数据库帮助程序实例,使用this
您指的是您的类的当前实例,因此您在每个方法中使用相同的数据库实例,因此当您调用finally块时RemoveNonceForMethod()
正在使用的数据库实例正在关闭。
尝试在方法中创建新对象: -
WebServicesDataManager dataManager = new WebServicesDataManager();
SQLiteDatabase db = dataManager.getWritableDatabase();
顺便说一下,你应该看看在Android中处理数据库的其他方法,如单例方法或使用contentprovider包装数据库!!
这里有几个链接: -
http://www.androiddesignpatterns.com/2012/05/correctly-managing-your-sqlite-database.html
What are the best practices for SQLite on Android?
答案 1 :(得分:0)
我敢打赌问题出在AddNonceForMethod
方法的这两行中:
...
RemoveNonceForMethod(method);
db = this.getWritableDatabase();
...
在RemoveNonceForMethod
中,你有这段代码:
finally {
if (db != null) {
// close database connection
db.close();
db = null;
}
}
由于finally
块将始终执行,因此在数据库关闭时,您肯定会退出此方法。然后,您离开RemoceNonceForMethod
,下一条指令是:
db = this.getWritableDatabase();
因此,您首先关闭,然后尝试重新打开同一个实例,因为getWritableDatabase()
会the following:
创建和/或打开将用于读写的数据库。第一次调用它时,将打开数据库并调用onCreate(SQLiteDatabase),onUpgrade(SQLiteDatabase,int,int)和/或onOpen(SQLiteDatabase)。
成功打开后,数据库将被缓存,因此您可以在每次需要写入数据库时调用此方法。 (确保在不再需要数据库时调用close()。)错误权限或完整磁盘等错误可能导致此方法失败,但如果问题得到解决,将来的尝试可能会成功。
这就是你获得例外的原因。