首页 > 解决方案 > 在返回光标的函数中关闭光标

问题描述

在我的 SQLite 类中关闭 Cursor 时遇到问题。当我关闭 Cursor 并SQLiteDatabase在 finally 块中 (in DBHelper) 时,我无法读取其他类中的数据(无法重新打开已关闭的 Cursor 错误)但是当我不关闭 Cursor 时SQLiteDatabase出现内存泄漏错误。

DHHelper.java:

//...
public Cursor selectData(String selectVal, String tabName){
    SQLiteDatabase db = this.getReadableDatabase();
    Cursor c = null;
    try {
        String areaTyp = "SELECT " + selectVal + "  FROM " + tabName;
        c = db.rawQuery(areaTyp, null);
        return c;
    } finally {
        c.close();
        db.close();
    }
}
//...

用户管理器.java

    public List<UserModel> getUsersList(){
    List<UserModel> allUsers = new ArrayList<UserModel>();

    final DBHelper db = new DBHelper(appStatic.CONTEX);
    Cursor c = db.selectData("*","User");
    if (c.moveToFirst()) {
        while (!c.isAfterLast()) {

            allUsers.add(new UserModel(c.getString(c.getColumnIndex("cms_id")),
                    c.getString(c.getColumnIndex("login")),
                            c.getString(c.getColumnIndex("name")),
                                    c.getString(c.getColumnIndex("active")),
                                            c.getString(c.getColumnIndex("avatar")),
                                                    c.getString(c.getColumnIndex("gtoken"))));

            c.moveToNext();
        }
    }
    c.close();
    db.close();

    return allUsers;
}

也许我应该以其他方式执行此操作,而返回 Cursor 的函数是个坏主意?

编辑: 当我运行应用程序时,我有错误:

java.lang.IllegalStateException:尝试重新打开一个已经关闭的对象:SQLiteQuery:SELECT * FROM User

在 UserMenager.java 中,行

if (c.moveToFirst()) {

标签: javaandroidandroid-sqlite

解决方案


我建议从selectData类中返回您想要的最终结果,即 ArrayList。然后,您可以在完成后立即关闭方法中的光标和数据库selectData

例如:-

public ArrayList<UserModel> selectData(String selectVal, String tabName){
    SQLiteDatabase db = this.getWritableDatabase(); //<<<< getReadable will most likely return a writeable database anyway
    ArrayList<UserModel> rv = new ArrayList<>();
    Cursor c = db.query(
            tabName,
            new String[]{selectVal},
            null,
            null,
            null,
            null,
            null
    );
    while (c.moveToNext()) {
        rv.add(new UserModel(
                c.getString(c.getColumnIndex("cms_id")),
                c.getString(c.getColumnIndex("login")),
                c.getString(c.getColumnIndex("name")),
                c.getString(c.getColumnIndex("active")),
                c.getString(c.getColumnIndex("avatar")),
                c.getString(c.getColumnIndex("gtoken"))
        ));
    }
    c.close();
    db.close();
    return rv;
}

随着 :-

public List<UserModel> getUsersList(){
    List<UserModel> allUsers = new ArrayList<UserModel>();

    final DBHelper db = new DBHelper(appStatic.CONTEX);
    return selectData("*","Users");
}
  • 包裹try/catch围绕 SQLiteDatabase 方法往往会导致更多的挫败感和混乱,而不是其他方式。
  • 通常推荐使用便捷方法而不是使用rawQueryandexecSQL方法(在这种情况下query是便捷方法)。
  • 理想情况下,selectVal应该是列的 String[] 而不仅仅是一个 String 以适应query方便的方法。
  • 正如所评论的那样getReadableDatabase,很少获得只读数据库
  • 创建和/或打开数据库。这将与 getWritableDatabase() 返回的对象相同,除非某些问题(例如磁盘已满)需要以只读方式打开数据库。在这种情况下,将返回一个只读数据库对象。如果问题得到解决,未来对 getWritableDatabase() 的调用可能会成功,在这种情况下,只读数据库对象将被关闭,并且将来会返回读/写对象。 SQLiteDatabase getReadableDatabase

推荐阅读