简体   繁体   English

Java非法状态异常

[英]Java illegal state exception

I am following a tutorial online, but i am getting an illegal state exception. 我正在在线上学习教程,但是却遇到了非法状态异常。 Link to tutorial: http://www.developerfeed.com/android/tutorial/building-todo-list-app-android-using-sqlite 链接至教程: http : //www.developerfeed.com/android/tutorial/building-todo-list-app-android-using-sqlite

Here is the Database class: 这是数据库类:

public class TaskerDbHelper extends SQLiteOpenHelper {

private static final int DATABASE_VERSION = 1;

// Database Name
private static final String DATABASE_NAME = "taskerManager";

// tasks table name
private static final String TABLE_TASKS = "tasks";

// tasks Table Columns names
private static final String KEY_ID = "id";
private static final String KEY_TASKNAME = "taskName";
private static final String KEY_STATUS = "status";

public TaskerDbHelper(Context context) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

@Override
public void onCreate(SQLiteDatabase db) {

    String sql = "CREATE TABLE IF NOT EXISTS " + TABLE_TASKS + " ( "
            + KEY_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + KEY_TASKNAME
            + " TEXT, " + KEY_STATUS + " INTEGER)";
    db.execSQL(sql);

    db.close();
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldV, int newV) {
    // Drop older table if existed
    db.execSQL("DROP TABLE IF EXISTS " + TABLE_TASKS);
    // Create tables again
    onCreate(db);
}

// Adding new task
public void addTask(Task task) {
    SQLiteDatabase db = this.getWritableDatabase();

    ContentValues values = new ContentValues();
    values.put(KEY_TASKNAME, task.getTaskName()); // task name
    // status of task- can be 0 for not done and 1 for done
    values.put(KEY_STATUS, task.getStatus());

    // Inserting Row
    db.insert(TABLE_TASKS, null, values);
    db.close(); // Closing database connection
}

public List<Task> getAllTasks() {
    List<Task> taskList = new ArrayList<Task>();
    // Select All Query
    String selectQuery = "SELECT  * FROM " + TABLE_TASKS;

    SQLiteDatabase db = this.getWritableDatabase();
    Cursor cursor = db.rawQuery(selectQuery, null);

    // looping through all rows and adding to list
    if (cursor.moveToFirst()) {
        do {
            Task task = new Task();
            task.setId(cursor.getInt(0));
            task.setTaskName(cursor.getString(1));
            task.setStatus(cursor.getInt(2));
            // Adding contact to list
            taskList.add(task);
        } while (cursor.moveToNext());
    }

    // return task list
    return taskList;
}

public void updateTask(Task task) {
    // updating row
    SQLiteDatabase db = this.getWritableDatabase();
    ContentValues values = new ContentValues();
    values.put(KEY_TASKNAME, task.getTaskName());
    values.put(KEY_STATUS, task.getStatus());
    db.update(TABLE_TASKS, values, KEY_ID + " = ?",new String[] {String.valueOf(task.getId())});
    db.close();
}

} }

And here is what the log file says: 日志文件显示的内容如下:

08-14 14:21:42.133: E/AndroidRuntime(10366): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.tasker/com.example.tasker.ViewTask}: java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /data/data/com.example.tasker/databases/taskerManager

There are two problems in your code: 您的代码中有两个问题:

A) you must not close the db in onCreate . A)您一定不能在onCreate关闭数据库。 That method is part of opening the db so the db should be open afterwards. 该方法是打开数据库的一部分,因此应在以后打开数据库。 source-code 源代码

public void onCreate(SQLiteDatabase db) {
    ...
    db.close();
}

B) You close the database at the end of every task. B)您在每个任务结束时关闭数据库。

public void updateTask(Task task) {
    db = get..
    ...
    db.close();
}

But while doing that you are still using the same database via a Cursor 但是这样做的同时,您仍然通过Cursor使用相同的数据库

db = db.get..
Cursor cursor = db.rawQuery
while (cursor.moveToNext() {
     updateTask();
}
db.close();

SQLiteOpenHelper will always give you the same db object since there is only one database. 由于只有一个数据库,因此SQLiteOpenHelper将始终为您提供相同的db对象。 Closing the connection in one method while using it in another one can lead to your problem as well. 在一种方法中关闭连接而在另一种方法中使用它也会导致您的问题。

You could probably solve the task problem by using the existing db object from the outer loop or simply not closing the db in updateTask but it is in practice much better not to close the database at all. 您可能可以通过使用外部循环中的现有db对象或根本不关闭updateTask的数据库来解决任务问题,但实际上最好不要完全关闭数据库。

Especially if you hand out references to Cursor . 特别是如果您分发对Cursor引用。 You must not close the database before the cursor is closed because Cursor can re-query it's data using the database connection it knows about. 关闭游标之前,请勿关闭数据库,因为Cursor可以使用它所了解的数据库连接来重新查询其数据。 That will happen in two cases: 这将在两种情况下发生:

If your code uses cursor.requery() probably indirectly through a bad CursorAdapter . 如果您的代码可能通过错误的CursorAdapter间接使用cursor.requery()

The second case is not as common. 第二种情况并不常见。 Cursor can only see a limited windows of the current query. Cursor只能看到当前查询的有限窗口。 If you move the cursor outside of that window it will re-query the required part using the database connection as well. 如果将光标移到该窗口之外,它也会使用数据库连接重新查询所需的部分。 Typical small databases are usually much smaller than the window so there is no need to move the window and no hidden requery will happen. 典型的小型数据库通常比窗口小得多,因此不需要移动窗口,也不会发生隐藏的重新查询。

Closing resources is usually a good thing. 关闭资源通常是一件好事。 Closing the database is in most cases not. 在大多数情况下,不是关闭数据库。 It is also no problem not doing it. 不这样做也没有问题。 SQLite makes sure nothing bad happens since every modification to the database is guaranteed by the transaction safety of SQLite. SQLite确保不会发生任何不良情况,因为SQLite的事务安全性保证了对数据库的每次修改。

you are closing the databse-connection at the end of each method with db.close(). 您将在每个方法的结尾使用db.close()关闭数据库连接。 So if you start another method you will always have to re-enable the connection. 因此,如果您启动其他方法,则将始终必须重新启用连接。 with

getWritableDatabase();

you should get it done. 您应该完成它。

Or you don't close the connection at the end of every method. 否则,您不必在每种方法结束时都关闭连接。 That totally depends on what your app is meant for. 这完全取决于您的应用程序的用途。

you have not called db.close(); 您尚未调用db.close(); in

      public List<Task> getAllTasks() { 
    .....

}

It may lead that problem because when you try to call getWritableDatabase(); 这可能导致该问题,因为当您尝试调用getWritableDatabase(); in next function at that time database is already being open. 那时下一个函数中的数据库已经打开。 so call db.close(); 所以调用db.close(); and close it in getAllTasks() method also. 并在getAllTasks()方法getAllTasks()其关闭。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM