在android sqlite中获取非法状态

时间:2014-04-18 18:17:19

标签: android sqlite android-sqlite

我写了一个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)

任何帮助???

2 个答案:

答案 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()。)错误权限或完整磁盘等错误可能导致此方法失败,但如果问题得到解决,将来的尝试可能会成功。

这就是你获得例外的原因。