我看到ContentProvider.query()返回一个Cursor对象。通常光标是SQLiteDatabase查询的结果。如下面的代码片段:
public Cursor query() {
try {
SQLiteDatabase db = this.getReadableDatabase();
Cursor c = db.query(Cfg.table_name, new String[] {"*"}, null, null, null, null, null);
return c;
}
catch(Exception exp) {
}
return null;
}
在代码中,db未关闭。有什么问题吗?
答案 0 :(得分:2)
是的,我相信存在问题。您可以将'db'作为参数传递,然后调用者可以在完成光标时关闭它。
答案 1 :(得分:1)
您是否在完成时尝试关闭数据库? 如果是这样,试试:
public Cursor query() {
SQLiteDatabase db = null;
try {
SQLiteDatabase db = this.getReadableDatabase();
Cursor c = db.query(Cfg.table_name, new String[] {"*"}, null, null, null, null, null);
return c;
}
catch(Exception exp) {
}finally{
try{if(null != db){ db.close(); db = null;}}catch(Exception e){}
}
return null;
}
每次都应该正确关闭数据库。如果你想知道它为什么没有关闭,我会调查一下Exception所说的内容。
顺便说一句,我会用null替换“new String [] {”*“}”。 http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html
更新:好的,我现在明白了这个问题。您可能需要重新调整一下您的课程。
TLDR:理想情况下,对我来说,最终应该是两个班级。一个是帮助您打开数据库。其次是将SQLiteDatabase对象作为属性。您可以在创建此类时立即打开连接并初始化DB对象(或创建用于打开数据库的方法)。所有方法仅将仅使用db对象的SCUD。然后,所有db对象关闭或分解都可以放在方法中或覆盖onDestroy。 以下示例,但如果您有空闲时间,这是一个很好的教程http://www.vogella.de/articles/AndroidSQLite/article.html。
第一个是DBOpenHelper。此类的目的是管理表并帮助您打开数据库以进行修改。
package com.mondial.th.rsa.db;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
/**
* DBOpenHelper helps opening database and managing database's upgrade or creation.
* @author Poohdish Rattanavijai
*
*/
public class DBOpenHelper extends SQLiteOpenHelper {
private static final String TAG = DBOpenHelper.class.getSimpleName();
private static final int DATABASE_VERSION = 2;
private static final String DATABASE_NAME = "rsa_db";
public DBOpenHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public DBOpenHelper(Context context, String name, CursorFactory factory,
int version) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase database) {
Log.d(TAG, "DBOpenHelper.onCreate");
// Create table goes here.
}
@Override
public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) {
// Drop and recreate table goes here.
}
}
第二个类将使用前面显示的DBOpenHelper为您处理所有查询。
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import com.mondial.th.rsa.vo.ProfileVO;
/**
* Database adapter for managing Profile table
* @author Poohdish Rattanavijai
*
*/
public class ProfileDBAdapter {
private static final String TAG = ProfileDBAdapter.class.getName();
private Context context;
private SQLiteDatabase db;
private DBOpenHelper dbHelper;
public ProfileDBAdapter(Context context){
this.context = context;
}
/**
* Open writable database.
* @return writable SQLDatabase
* @throws SQLException
*/
public ProfileDBAdapter open() throws SQLException{
Log.d(TAG, "Open ProfileDBAdapter");
dbHelper = new DBOpenHelper(context);
db = dbHelper.getWritableDatabase();
return this;
}
/**
* Close database; Exception omitted
*/
public void close(){
try {
dbHelper.close();
} catch (Exception e) {
//e.printStackTrace();
}
}
/**
* Creating new record in profile table with given VO.
* @param profile VO representing data in the new record.
* @return the row ID of the newly inserted row, or -1 if an error occurred.
*/
public long createProfile(ProfileVO profile){
ContentValues values = createContentValues(profile);
return db.insert(ProfileVO.TABLE_NAME, null, values);
}
/**
* Updating record in profile table with given VO by using ID column.
* @param profile VO representing new data to updated.
* @return the number of rows affected .
*/
public boolean updateProfile(ProfileVO profile){
ContentValues values = createContentValues(profile);
return db.update(ProfileVO.TABLE_NAME, values, ProfileVO.COLUMN_ID + "=" + profile.getId(), null) > 0;
}
/**
* Deleting a row representing given VO off profile table by using ID column.
* @param profile
* @return
*/
public boolean deleteProfile(ProfileVO profile){
return deleteProfile(profile.getId());
}
/**
* Deleting a row off profile table with given ID column.
* @param profile
* @return
*/
public boolean deleteProfile(long rowId){
return db.delete(ProfileVO.TABLE_NAME, ProfileVO.COLUMN_ID + "=" + rowId, null) > 0;
}
/**
* open cursor representing every records in profile table.
* @return Cursor representing every records in profile table.
*/
public Cursor fetchAllProfiles(){
return db.query(ProfileVO.TABLE_NAME, null, null, null, null, null, null);
}
/**
* open cursor representing a row in profile table with given ID.
* @return Cursor representing a row in profile table with given ID.
*/
public Cursor fetchProfile(long rowId){
Cursor mCursor = db.query(true, ProfileVO.TABLE_NAME, null, ProfileVO.COLUMN_ID + "=" + rowId
, null, null, null, null, null);
if(null != mCursor){
mCursor.moveToFirst();
}
return mCursor;
}
/**
* This class translate given VO into ContentValues for ContentResolver to parse data and talk to the database.
* @param profile VO
* @return ContentsValues containing given VO's data except ID.
*/
private ContentValues createContentValues(ProfileVO profile){
ContentValues values = new ContentValues();
values.put(ProfileVO.COLUMN_DOB, profile.getDob());
values.put(ProfileVO.COLUMN_FIRSTNAME, profile.getFirstname());
values.put(ProfileVO.COLUMN_LASTNAME, profile.getLastname());
return values;
}
}
然后你有一个完美的课程充当DAO。对于上面的例子,用法是。
ProfileDBAdapter dbHelper = new ProfileDBAdapter(context);
dbHelper.open();
cursor = dbHelper.fetchAllProfiles();
if(cursor.getCount() > 0){
//TODO Data exists, do stuff.
}
try {
if(null != cursor && !cursor.isClosed()){
cursor.close();
}
} catch (Exception e) {
e.printStackTrace();
}
if(null != dbHelper){
dbHelper.close();
dbHelper = null;
}