0

大家好,我是 Android 新手,我正在使用 SQLiteDataBase,我收到关于光标未关闭的错误,这不是致命的,但很烦人。就这个。

01-14 15:53:42.503: E/Cursor(1090): Finalizing a Cursor that has not been deactivated or closed. database = /data/data/uk.ac.tees.L1087591/databases/Wettboff.db, table = webpages, query = SELECT _id, url, source, date FROM webpages WHERE _id=?
01-14 15:53:42.503: E/Cursor(1090): android.database.sqlite.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here
01-14 15:53:42.503: E/Cursor(1090):     at android.database.sqlite.SQLiteCursor.<init>(SQLiteCursor.java:210)
01-14 15:53:42.503: E/Cursor(1090):     at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:53)
01-14 15:53:42.503: E/Cursor(1090):     at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1345)
01-14 15:53:42.503: E/Cursor(1090):     at android.database.sqlite.SQLiteDatabase.queryWithFactory(SQLiteDatabase.java:1229)
01-14 15:53:42.503: E/Cursor(1090):     at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1184)
01-14 15:53:42.503: E/Cursor(1090):     at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1301)
01-14 15:53:42.503: E/Cursor(1090):     at uk.ac.tees.L1087591.DatabaseHandler.getWebPage(DatabaseHandler.java:237)
01-14 15:53:42.503: E/Cursor(1090):     at uk.ac.tees.L1087591.Web.onCreate(Web.java:54)
01-14 15:53:42.503: E/Cursor(1090):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
01-14 15:53:42.503: E/Cursor(1090):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
01-14 15:53:42.503: E/Cursor(1090):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
01-14 15:53:42.503: E/Cursor(1090):     at android.app.ActivityThread.access$2300(ActivityThread.java:125)
01-14 15:53:42.503: E/Cursor(1090):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
01-14 15:53:42.503: E/Cursor(1090):     at android.os.Handler.dispatchMessage(Handler.java:99)
01-14 15:53:42.503: E/Cursor(1090):     at android.os.Looper.loop(Looper.java:123)
01-14 15:53:42.503: E/Cursor(1090):     at android.app.ActivityThread.main(ActivityThread.java:4627)
01-14 15:53:42.503: E/Cursor(1090):     at java.lang.reflect.Method.invokeNative(Native Method)
01-14 15:53:42.503: E/Cursor(1090):     at java.lang.reflect.Method.invoke(Method.java:521)
01-14 15:53:42.503: E/Cursor(1090):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
01-14 15:53:42.503: E/Cursor(1090):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
01-14 15:53:42.503: E/Cursor(1090):     at dalvik.system.NativeStart.main(Native Method)

这是对数据库的抱怨。

01-14 15:53:42.653: E/Database(1090): close() was never explicitly called on database '/data/data/uk.ac.tees.L1087591/databases/Wettboff.db' 
01-14 15:53:42.653: E/Database(1090): android.database.sqlite.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here
01-14 15:53:42.653: E/Database(1090):   at android.database.sqlite.SQLiteDatabase.<init>(SQLiteDatabase.java:1810)
01-14 15:53:42.653: E/Database(1090):   at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:817)
01-14 15:53:42.653: E/Database(1090):   at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:851)
01-14 15:53:42.653: E/Database(1090):   at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:844)
01-14 15:53:42.653: E/Database(1090):   at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:540)
01-14 15:53:42.653: E/Database(1090):   at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:203)
01-14 15:53:42.653: E/Database(1090):   at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:98)
01-14 15:53:42.653: E/Database(1090):   at android.database.sqlite.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:158)
01-14 15:53:42.653: E/Database(1090):   at uk.ac.tees.L1087591.DatabaseHandler.getWebPage(DatabaseHandler.java:236)
01-14 15:53:42.653: E/Database(1090):   at uk.ac.tees.L1087591.Web.onCreate(Web.java:54)
01-14 15:53:42.653: E/Database(1090):   at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
01-14 15:53:42.653: E/Database(1090):   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
01-14 15:53:42.653: E/Database(1090):   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
01-14 15:53:42.653: E/Database(1090):   at android.app.ActivityThread.access$2300(ActivityThread.java:125)
01-14 15:53:42.653: E/Database(1090):   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
01-14 15:53:42.653: E/Database(1090):   at android.os.Handler.dispatchMessage(Handler.java:99)
01-14 15:53:42.653: E/Database(1090):   at android.os.Looper.loop(Looper.java:123)
01-14 15:53:42.653: E/Database(1090):   at android.app.ActivityThread.main(ActivityThread.java:4627)
01-14 15:53:42.653: E/Database(1090):   at java.lang.reflect.Method.invokeNative(Native Method)
01-14 15:53:42.653: E/Database(1090):   at java.lang.reflect.Method.invoke(Method.java:521)
01-14 15:53:42.653: E/Database(1090):   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
01-14 15:53:42.653: E/Database(1090):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
01-14 15:53:42.653: E/Database(1090):   at dalvik.system.NativeStart.main(Native Method)

这是我的 DatabaseHandler 类

public class DatabaseHandler extends SQLiteOpenHelper {

    /**
     * The name of the database
     */
     protected static final String DATABASE_NAME = "Wettboff.db";

    /**
     * The name of the table.
     */
     protected static final String TABLE_NAME = "webpages";

    /**
     * The name of the first column (ID)
     */
     protected static final String COL_ID = "_id";

    /**
     * The name of the second column (URL)
     */
     protected static final String COL_url = "url";

    /**
     * The name of the third column (source)
     */
     protected static final String COL_source = "source";

     /**
      * The name of the fourth column (date)
      */
     protected static final String COL_date = "date";

    /**
     * A constructor which builds a DatabaseHandler object. Note that calling
     * the constructor does not create a database. This does not happen until
     * the first call to getReadableDatabase() or getWriteableDatabase()
     * 
     * @param context ,  In this case, a reference to webpageActivity
     */
    public DatabaseHandler(Context context) {
        super(context, DATABASE_NAME, null, 1);
    }

    /**
     * This method is called when the database is created for the first time.
     * This is where the creation of tables and the initial population of the
     * tables should happen.
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        String CREATE_CONTACTS_TABLE = "CREATE TABLE " + TABLE_NAME + "("
                + COL_ID + " INTEGER PRIMARY KEY," + COL_url + " TEXT,"
                + COL_source + " TEXT," + COL_date + " TEXT" + ");";
        Log.d("Table name in onCreate", TABLE_NAME);
        db.execSQL(CREATE_CONTACTS_TABLE);
        Log.d("WebOff", "Database populated");
    }

    /**
     * Called when the database needs to be upgraded. Only relevant when you
     * have multiple versions of the database scheme in play.
     * 
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldNum, int newNum) {
        // Drop older table if exist and create fresh
        Log.w("Updating database: ", " Upgrading database from version " + oldNum
                + " to "
                + newNum + ", which will destroy all old data");
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
        onCreate(db);
    }

    /**
     * Use this method to add a webpage to the database.
     * 
     * @param webpage
     *            the webpage you want to add
     */
    public void addWebPage(List<WebPage> webpage) {
        SQLiteDatabase db = this.getWritableDatabase();
        ContentValues values = new ContentValues();
        for (WebPage lr : webpage) {
            values.put(COL_ID, lr.getID());
            values.put(COL_url, lr.getUrl());
            values.put(COL_source, lr.getSource());
            values.put(COL_date, lr.getDate());
        }
        db.insert(TABLE_NAME, null, values);
        db.close();
    }

    /**
     * Use this method to add a webpage to the database.
     * 
     * @param webpage
     *            the webpage you want to add
     */
    public void addWebPage(WebPage webpage) {
        SQLiteDatabase db = this.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put(COL_ID, webpage.getID());
        values.put(COL_url, webpage.getUrl());
        values.put(COL_source, webpage.getSource());
        values.put(COL_date, webpage.getDate());
        db.insert(TABLE_NAME, null, values);
        db.close();
    }

    /**
     * Use this method to get all of the webpages in the database.
     * 
     * @return a list of webpage objects, one per row
     */
    public List<WebPage> getAll() {
        List<WebPage> list = new ArrayList<WebPage>();
        String selectQuery = "SELECT  * FROM " + TABLE_NAME;
        SQLiteDatabase db = this.getReadableDatabase();
        Cursor cursor = db.rawQuery(selectQuery, null);
        if (cursor.moveToFirst()) {
            do {
                WebPage webpage = new WebPage(cursor.getInt(0),
                        cursor.getString(1), cursor.getString(2), cursor.getLong(3));
                list.add(webpage);
            } while (cursor.moveToNext());
        }
        return list;
    }


    /**
     * Use this method to get a Cursor object that points at all the webpages in 
     * the database
     * 
     * @return a Cursor object pointing at all webpages in db
     */
    public Cursor getAllAsCursor() {
        String selectQuery = "SELECT  * FROM " + TABLE_NAME;
        SQLiteDatabase db = this.getReadableDatabase();
        Cursor cursor = db.rawQuery(selectQuery, null);
        return cursor;
    }

    /**
     * Use this method to remove all of the webpages from the database. This is
     * useful when experimenting. After dropping all tables, the initial state
     * of the database is re-created.
     */
    public void removeAll() {
        SQLiteDatabase db = this.getWritableDatabase();
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
        onCreate(db);
    }

    /**
     * This method removes one webpage from the database.
     * 
     * @param webpage
     *            the webpage to remove
     */
    public void deletewebpage(int id) {
        SQLiteDatabase db = this.getWritableDatabase();

        db.delete(TABLE_NAME, COL_ID + " = ?",
                new String[] { String.valueOf(id)});
        db.close();
    }

    /**
     * This method updates the data stored in the database for one webpage.
     * 
     * @param webpage
     *            the webpage to update
     * @return the number of rows affected
     */
    public int updateWebPage(WebPage pages) {

            SQLiteDatabase db = this.getWritableDatabase();
            ContentValues values = new ContentValues();
//          values.put(COL_ID, lr.getID());
            values.put(COL_url, pages.getUrl());
            values.put(COL_source, pages.getSource());
            values.put(COL_date, pages.getDate());
            return db.update(TABLE_NAME, values, COL_ID + " = ?",
                    new String[] { String.valueOf(((WebPage) pages).getID()) });
    }


    /**  
     * This method gets a single webpage from the database, using the ID field
     * as a key
     * ;
     * @param id
     *            the ID of the webpage we want
     * @return a webpage object
     */
    public WebPage getWebPage(int id) {
        SQLiteDatabase db = this.getReadableDatabase();
        Cursor cursor = db.query(TABLE_NAME, new String[] { COL_ID, COL_url,
                COL_source, COL_date }, COL_ID + "=?",
                new String[] { String.valueOf(id) }, null, null, null, null);
        if (cursor != null) {
            cursor.moveToFirst();
        }
        WebPage webpage = new WebPage(Integer.parseInt(cursor.getString(0)),
                cursor.getString(1), cursor.getString(2), cursor.getLong(3));
        return webpage;
    }
}

当我尝试使用以下代码阅读多个网页时

public class Read extends MenuActivity {

    /**
     * sca is an object of type SimpleCursorAdapter and we use it to set the
     * adapter.
     */
    private SimpleCursorAdapter sca;

    /**
     * dh is an object of type DatabaseHandler and we use it to connet to the
     * data base.
     */
    private DatabaseHandler dh;

    /**
     * mainListView is a List View.
     */
    private ListView mainListView;

    /**
     * context is a Content that takes the current one(this)
     */
    private final Context context = this;

    /**
     * myId stores the id of the selected url
     */
    protected static int myId;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_read);
        mainListView = (ListView) findViewById(R.id.mainListView);
        dh = new DatabaseHandler(this);

        /**
         * Get a Cursor pointing at all web pages in the database
         */
        final Cursor cursor = dh.getAllAsCursor();

        /**
         * cols gets the value of the COL_url
         */
        String[] cols = new String[] { DatabaseHandler.COL_url };

        /**
         * to get the value of the url_entry.
         */
        int[] to = new int[] { R.id.url_entry };
        sca = new SimpleCursorAdapter(this, R.layout.read, cursor, cols, to, 2);
        mainListView.setAdapter(sca);
        mainListView.showContextMenu();
        registerForContextMenu(mainListView);


        // when the user does a longclick
        mainListView.setOnItemLongClickListener(new OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
                    int id, long arg3) {
                myId = id;
                Log.d("WebOff ",
                        "Web page read:  id number in OnItemLongCLick " + id);
                cursor.close();
                return false;
            }
        });

    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v,
            ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
        menu.setHeaderTitle("WebOff Menu");
        menu.add(0, v.getId(), 0, "Read using WebOff");
        menu.add(0, v.getId(), 0, "Read using web browser");
    }

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        if (item.getTitle() == "Read using WebOff") {
            readUsingWebOff(item.getItemId());
        } else if (item.getTitle() == "Read using web browser") {
            readUsingWebBrowser(item.getItemId());
        } else {
            return false;
        }
        return true;
    }

    /**
     * readUsingWebOff goes to the Web activity.
     * 
     * @param id
     *            of the web Page
     */
    public void readUsingWebOff(int id) {
        Toast.makeText(this, "WebOff called", Toast.LENGTH_SHORT).show();
        Intent k = new Intent(context, Web.class);
        startActivity(k);
    }

    /**
     * readUsingWebBrowser() reads the web pages through the web broweser.
     * 
     * @param id
     *            of the web page.
     */
    public void readUsingWebBrowser(int id) {
        Toast.makeText(this, "Web browser called", Toast.LENGTH_SHORT).show();
        WebPage page = dh.getWebPage(Read.myId);
        String myUrl = page.getUrl();
        Uri uri = Uri.parse(myUrl);

//      dh.close();

        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        startActivity(intent);
    }

}

我得到光标异常。

4

3 回答 3

4

您需要正确关闭游标和数据库。将您的 getWebPage() 方法修改为以下内容:

public WebPage getWebPage(int id) {
    SQLiteDatabase db = this.getReadableDatabase();
    Cursor cursor = db.query(TABLE_NAME, new String[] { COL_ID, COL_url,
            COL_source, COL_date }, COL_ID + "=?",
            new String[] { String.valueOf(id) }, null, null, null, null);
    WebPage webpage = null;
    if (cursor != null) {
        if (cursor.moveToFirst()) {
            webpage = new WebPage(Integer.parseInt(cursor.getString(0)), cursor.getString(1), cursor.getString(2), cursor.getLong(3));
        }
        cursor.close();
    }
    return webpage; // be aware, it might return null now!
}
于 2013-01-14T16:03:56.130 回答
0

称呼:

cursor.close();

只要你有一个打开的光标,你就完成了(即在你的getAll()方法中)。

于 2013-01-14T16:04:50.977 回答
0

您应该在 finally try-catch 中关闭数据库连接

String sqlQuery = "SELECT ....";

    Cursor c = null;
    try {
        c = this.rawQuery(sqlQuery, new String[] { params });
        if (c.moveToFirst()) {
            do {
                parseCusors(c);
            } while (c.moveToNext());
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (c != null) {
            try {c.close();} catch (Exception ignore) {;}
        }
    }
于 2014-09-09T03:22:44.050 回答