2013-08-14 4 views
1

Я следую учебнику онлайн, но я получаю исключение из незаконного состояния. Ссылка на учебник: http://www.developerfeed.com/android/tutorial/building-todo-list-app-android-using-sqliteЯвное незаконное государственное исключение

Вот класс базы данных:

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(); 
} 

}

А вот что говорится в файле журнала:

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 

ответ

2

вы закрываете Databse -соединение в конце каждого метода с помощью db.close(). Итак, если вы запустите другой метод, вам всегда нужно будет снова включить соединение. с

getWritableDatabase(); 

вы должны сделать это.

Или вы не закрываете соединение в конце каждого метода. Это полностью зависит от того, для чего предназначено ваше приложение.

1

вы не вызвали db.close(); в

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

} 

Это может привести эту проблему, потому что, когда вы пытаетесь вызвать getWritableDatabase(); в следующей функции в то время базы данных уже открыт. поэтому звоните db.close(); и закройте его в getAllTasks() способ тоже.

3

Есть две проблемы в вашем коде:

A) вы не должны закрывать дб в onCreate. Этот метод является частью открытия db, поэтому db должен быть открыт после этого. source-code

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

B) Вы закрываете базу данных в конце каждой задачи.

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

Но при этом, что вы все еще используете ту же базу данных всегда даст вам тот же db объект, так как есть только одна база данных через Cursor

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

SQLiteOpenHelper. Закрытие соединения одним способом при использовании его в другом может привести к вашей проблеме.

Возможно, вы решили решить задачу с помощью существующего объекта db из внешнего цикла или просто не закрывать db в updateTask, но на практике гораздо лучше не закрывать базу данных вообще.

Особенно, если вы передаете ссылки на Cursor. Вы не должны закрывать базу данных до того, как курсор закрыт, потому что Cursor может повторно запросить данные, используя соединение с базой данных, о котором он знает. Это произойдет в двух случаях:

Если ваш код использует cursor.requery(), возможно, косвенно через плохой CursorAdapter.

Второй случай не является общим.Cursor может видеть только ограниченное окно текущего запроса. Если вы переместите курсор за пределы этого окна, он снова запросит требуемую часть, используя соединение с базой данных. Типичные небольшие базы данных обычно намного меньше, чем окно, поэтому нет необходимости перемещать окно, и скрытая просьба не будет выполняться.

Закрытие ресурсов, как правило, хорошо. Закрытие базы данных в большинстве случаев отсутствует. Это также не проблема, если не делать этого. SQLite гарантирует, что ничего плохого не происходит, поскольку каждая модификация базы данных гарантируется безопасностью транзакций SQLite.

Смежные вопросы