无法返回 Cursor 对象 - close() 从未明确调用错误

发布于 2024-10-31 17:44:09 字数 3898 浏览 2 评论 0原文

嘿。我正在尝试将光标对象返回到我的活动,它将在 SimpleCursorAdapter 中使用,但我遇到 close() was never Explyy Called 错误。我找不到此错误的任何解决方案,并且我认为这是一个非解决方案错误,哈哈。

和我一起思考。

错误说:

close() 从未被显式调用过 数据库 '/data/data/com.example.myapp/databases/myDB.db'

并且也有一个警告:

在终结器中释放语句。 请确保您明确致电 close() 光标处:SELECT * FROM contact_data ORDER BY 持续时间说明

android.database.sqlite.DatabaseObjectNotClosedException: 应用程序未关闭此处打开的游标或数据库对象

错误出在该方法中,即在类 DataHandlerDB(处理数据库)中

public static Cursor selectTopCalls(Context ctx) {

        OpenHelper helper = new OpenHelper(ctx);
        SQLiteDatabase db = helper.getWritableDatabase(); // error is here

        Cursor cursor = db.query(TABLE_NAME_2, null, null, null, null, null,
                "duration desc");

        return cursor;
    }

该方法通过以下方法在我的活动中使用:

public void setBasicContent() {

    listview = (ListView) findViewById(R.id.list_view); 

    Log.i(LOG_TAG, "listview " + listview);

    Cursor c = DataHandlerDB.selectTopCalls(this); // here I use the method
    startManagingCursor(c);

    adapter = new SimpleCursorAdapter(this, R.layout.list_item, c, new String[] {               
            DataHandlerDB.CONTACT_NAME_COL,
            DataHandlerDB.CONTACT_NUMBER_COL,
            DataHandlerDB.CONTACT_DURATION_COL,
            DataHandlerDB.CONTACT_DATE_COL }, new int[] {
            R.id.contact_name, R.id.phone_number, R.id.duration, R.id.date });

    Log.i(LOG_TAG, "before setAdapter");

    Toast.makeText(this, "Before setAdapter", Toast.LENGTH_SHORT).show();

    listview.setAdapter(adapter);


}

我尝试关闭游标和此方法内的数据库,但是当我这样做时,错误未修复,并且它不打印我的列表。

我尝试在 selectValues() 方法上关闭它,但是当这样做时,它说尝试重新打开已经关闭的光标(类似的)。

我还尝试在 onDestroy()、onStop() 中关闭游标和数据库,但没有成功。

这就是为什么我认为没有解决方案。我该怎么办?

DataHandlerDB.java 有一个 createDB() 方法:

public static SQLiteDatabase createDB(Context ctx) {
        OpenHelper helper = new OpenHelper(ctx);
        SQLiteDatabase db = helper.getWritableDatabase();
        helper.onOpen(db);
        db.close();
        return db;
    }

和一个名为 OpenHelper(extends SQLiteOpenHelper) 的内部类

public static class OpenHelper extends SQLiteOpenHelper {

        private final Context mContext;

        OpenHelper(Context context) {

            super(context, DATABASE_NAME, null, DATABASE_VERSION);
            this.mContext = context;

        }

        @Override
        public void onCreate(SQLiteDatabase db) {

            String[] sql = mContext.getString(
                    R.string.MyString_OnCreate).split("\n");

            db.beginTransaction();

            try {
                execMultipleSQL(db, sql);
                db.setTransactionSuccessful();
            } catch (SQLException e) {

                Log.e("Error creating tables and debug data", e.toString());
                throw e;

            } finally {
                db.endTransaction();

            }
        }

        private void execMultipleSQL(SQLiteDatabase db, String[] sql) {

            for (String s : sql) {

                if (s.trim().length() > 0) {

                    db.execSQL(s);
                }
            }

        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            /*
             * Log.w("My Database",
             * "Upgrading database, this will drop tables and recreate.");
             * db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME); onCreate(db);
             */
        }

        @Override
        public void onOpen(SQLiteDatabase db) {

            super.onOpen(db);
        }

    }

所以任何人都可以帮助我解决这个问题?谢谢!

Hey. I'm trying to return a cursor object to my activity where its gonna be used in a SimpleCursorAdapter, but Im having a close() was never explicity called error. I cant find any solution for this error, and I'm about to think that its a non-solution error, LOL.

Think with me.

The error says:

close() was never explicitly called on
database
'/data/data/com.example.myapp/databases/myDB.db'

And has a warning too:

Releasing statement in a finalizer.
Please ensure that you explicitly call
close() on your cursor: SELECT * FROM
contact_data ORDER BY duration desc

android.database.sqlite.DatabaseObjectNotClosedException:
Application did not close the cursor or database object that was opened here

The error is in this method, that is in the class DataHandlerDB (deals with database)

public static Cursor selectTopCalls(Context ctx) {

        OpenHelper helper = new OpenHelper(ctx);
        SQLiteDatabase db = helper.getWritableDatabase(); // error is here

        Cursor cursor = db.query(TABLE_NAME_2, null, null, null, null, null,
                "duration desc");

        return cursor;
    }

This method is used on my activity, by this following method:

public void setBasicContent() {

    listview = (ListView) findViewById(R.id.list_view); 

    Log.i(LOG_TAG, "listview " + listview);

    Cursor c = DataHandlerDB.selectTopCalls(this); // here I use the method
    startManagingCursor(c);

    adapter = new SimpleCursorAdapter(this, R.layout.list_item, c, new String[] {               
            DataHandlerDB.CONTACT_NAME_COL,
            DataHandlerDB.CONTACT_NUMBER_COL,
            DataHandlerDB.CONTACT_DURATION_COL,
            DataHandlerDB.CONTACT_DATE_COL }, new int[] {
            R.id.contact_name, R.id.phone_number, R.id.duration, R.id.date });

    Log.i(LOG_TAG, "before setAdapter");

    Toast.makeText(this, "Before setAdapter", Toast.LENGTH_SHORT).show();

    listview.setAdapter(adapter);


}

I try to close the cursor and database inside this method, but when I do that, the error is not fixed, and it doesnt print my list.

I tried to close it on the selectValues() method, but when doing that, it says, trying to re-open cursor already closed (something like that).

I also tried to close the cursor and database in onDestroy(), onStop() but it didnt worked.

Thats why I thought there were no soluytion for that. What am I supose to do?

The class DataHandlerDB.java, has a createDB() method:

public static SQLiteDatabase createDB(Context ctx) {
        OpenHelper helper = new OpenHelper(ctx);
        SQLiteDatabase db = helper.getWritableDatabase();
        helper.onOpen(db);
        db.close();
        return db;
    }

And an Inner Class called OpenHelper(extends SQLiteOpenHelper)

public static class OpenHelper extends SQLiteOpenHelper {

        private final Context mContext;

        OpenHelper(Context context) {

            super(context, DATABASE_NAME, null, DATABASE_VERSION);
            this.mContext = context;

        }

        @Override
        public void onCreate(SQLiteDatabase db) {

            String[] sql = mContext.getString(
                    R.string.MyString_OnCreate).split("\n");

            db.beginTransaction();

            try {
                execMultipleSQL(db, sql);
                db.setTransactionSuccessful();
            } catch (SQLException e) {

                Log.e("Error creating tables and debug data", e.toString());
                throw e;

            } finally {
                db.endTransaction();

            }
        }

        private void execMultipleSQL(SQLiteDatabase db, String[] sql) {

            for (String s : sql) {

                if (s.trim().length() > 0) {

                    db.execSQL(s);
                }
            }

        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            /*
             * Log.w("My Database",
             * "Upgrading database, this will drop tables and recreate.");
             * db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME); onCreate(db);
             */
        }

        @Override
        public void onOpen(SQLiteDatabase db) {

            super.onOpen(db);
        }

    }

So anyone can help me to fix this problem?? Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

歌枕肩 2024-11-07 17:44:09

不要在每个静态方法中创建新的 OpenHelper,而是使用当前上下文实例化 DataHandlerDB 并让该类保存由 getWritableDatabase 填充的变量。您正在创建由不同 SQLiteOpenHelper 对象创建的多个游标对象,而 Android 不喜欢这样做。

查看此以获取更多信息:http://www.ragtag.info/2011 /feb/1/database-pitfalls/

在我看来,您正在做的事情是这样的...

public class DataHandlerDB{

    public static SQLiteDatabase createDB(Context ctx) {
        OpenHelper helper = new OpenHelper(ctx);
        SQLiteDatabase db = helper.getWritableDatabase();
        ...
        return db;
    }

    public static Cursor selectTopCalls(Context ctx) {
        OpenHelper helper = new OpenHelper(ctx);
        SQLiteDatabase db = helper.getWritableDatabase(); // error is here
        ...
        return c;
    }

}

这会导致多个并发 SQLiteOpenHelper 对象和多个 SQLiteDatabase 对象以及您当前拥有的锁定情况。

不要执行多个静态调用,而是创建一个使用一致上下文实例化的 DataHandler 类,然后进行正常调用(而不是静态调用):

public class DataHandlerDB{
    OpenHelper _helper;
    SQLiteDatabse _db;

    public DataHandlerDB( Context ctx ){
        _helper = new OpenHelper(ctx);
        _db = _helper.getWritableDatabase();
    }

    public SQLiteDatabase createDB() {
        ...
        return db;
    }

    public Cursor selectTopCalls() {
        ...
        return c;
    }

}

public void setBasicContent() {

    ...

    DataHandlerDB handler = new DataHandlerDB( this );
    Cursor c = handler.selectValues();  //.selectTopCalls()?

    ...
}

当您创建此对象时,它将保留 1 OpenHelper 和 1 SQLite数据库。这应该可以缓解 SQLite 在访问数据库之前需要关闭数据库的问题。

不要忘记在 Activity 的 onDestroy 方法中关闭数据库。

Instead of creating a new OpenHelper in each of your static methods, instantialize your DataHandlerDB with the current context and have the class hold a variable populated by getWritableDatabase. You are creating multiple cursor objects created by different SQLiteOpenHelper objects and Android doesn't like doing this.

Check this out for additional info: http://www.ragtag.info/2011/feb/1/database-pitfalls/

Here's how it looks to me like you're doing things...

public class DataHandlerDB{

    public static SQLiteDatabase createDB(Context ctx) {
        OpenHelper helper = new OpenHelper(ctx);
        SQLiteDatabase db = helper.getWritableDatabase();
        ...
        return db;
    }

    public static Cursor selectTopCalls(Context ctx) {
        OpenHelper helper = new OpenHelper(ctx);
        SQLiteDatabase db = helper.getWritableDatabase(); // error is here
        ...
        return c;
    }

}

This results in multiple concurrent SQLiteOpenHelper objects and multiple SQLiteDatabase objects and the locking situation you currently have.

Instead of doing multiple Static calls, make a DataHandler class that you instantialize with the consistent context and then make normal calls (instead of static ones):

public class DataHandlerDB{
    OpenHelper _helper;
    SQLiteDatabse _db;

    public DataHandlerDB( Context ctx ){
        _helper = new OpenHelper(ctx);
        _db = _helper.getWritableDatabase();
    }

    public SQLiteDatabase createDB() {
        ...
        return db;
    }

    public Cursor selectTopCalls() {
        ...
        return c;
    }

}

public void setBasicContent() {

    ...

    DataHandlerDB handler = new DataHandlerDB( this );
    Cursor c = handler.selectValues();  //.selectTopCalls()?

    ...
}

When you create this object, it will persist 1 OpenHelper and 1 SQLiteDatabase. This should alleviate the problems with SQLite wanting the database closed before it can access it.

Don't forget to close the DB in the onDestroy method of your activity.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文