大家好,我是 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);
}
}
我得到光标异常。