Java 无法返回游标对象-从未显式调用close()错误

Java 无法返回游标对象-从未显式调用close()错误,java,android,sqlite,jdbc,cursor,Java,Android,Sqlite,Jdbc,Cursor,嘿。我试图将游标对象返回到我的活动中,它将在SimpleCorsOrAdapter中使用,但我遇到了一个close()从未被显式调用的错误。我找不到任何解决这个错误的方法,我想这是一个无法解决的错误,哈哈 跟我想想 错误显示: close()从未被显式调用 数据库 “/data/data/com.example.myapp/databases/myDB.db” 还有一个警告: 在终结器中释放语句。 请确保您明确地调用 在光标上关闭():从中选择* 按持续时间描述联系_数据顺序 android.d

嘿。我试图将游标对象返回到我的活动中,它将在SimpleCorsOrAdapter中使用,但我遇到了一个
close()从未被显式调用的错误。我找不到任何解决这个错误的方法,我想这是一个无法解决的错误,哈哈

跟我想想

错误显示:

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

还有一个警告:

在终结器中释放语句。 请确保您明确地调用 在光标上关闭():从中选择* 按持续时间描述联系_数据顺序

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

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

此方法通过以下方法用于我的活动:

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()方法:

还有一个名为OpenHelper的内部类(扩展了SQLiteOpenHelper)


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

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

有关其他信息,请查看此链接:

在我看来,这就是你在做的事情

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类,然后进行常规调用(而不是静态调用):

创建此对象时,它将保持1
OpenHelper
和1
SQLiteDatabase
。这将缓解SQLite希望在访问数据库之前关闭数据库的问题


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

当你说:用当前上下文实例化DataHandlerDB,让类包含一个由getWritableDatabase填充的变量时,我不明白。你能给我举个清楚的例子吗?谢谢我按你说的做了。但它一直显示相同的错误,但现在在DataHandlerDB构造函数的行中:_db=_helper.getWritableDatabase()@cyberrog你可能在某处仍然有一个开放的连接。您是否已关闭其他活动中以前的所有连接?如果您使用我概述的方法,那么请确保在使用完DB后也调用了
handler.close()
public static SQLiteDatabase createDB(Context ctx) {
        OpenHelper helper = new OpenHelper(ctx);
        SQLiteDatabase db = helper.getWritableDatabase();
        helper.onOpen(db);
        db.close();
        return db;
    }
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);
        }

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

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

    ...
}