Android SQLite数据库关闭查询()
我看到ContentProvider.query()返回一个游标对象。通常,游标是SQLiteDatabase查询的结果。如下代码段所示:Android SQLite数据库关闭查询(),android,sqlite,Android,Sqlite,我看到ContentProvider.query()返回一个游标对象。通常,游标是SQLiteDatabase查询的结果。如下代码段所示: public Cursor query() { try { SQLiteDatabase db = this.getReadableDatabase(); Cursor c = db.query(Cfg.table_name, new String[] {"*"}, null, nu
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未关闭。有什么问题吗?完成后是否尝试关闭数据库? 如果是,请尝试:
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;
}
每次都应该正确关闭数据库。如果您想知道为什么它没有关闭,我会调查捕获的异常是什么意思
顺便说一下,我会用null替换“newstring[]{“*”}”。
更新:好了,现在我明白问题了。不过,您可能需要重新构造您的类
TLDR:对我来说,理想的结局是两门课。一个是帮助你打开数据库。第二种方法是将SQLiteDatabase对象作为属性保存。您可以在创建此类(或创建用于打开数据库的方法)后立即打开连接并初始化DB对象。所有方法仅将db对象用于SCUD。然后,所有db对象关闭或分解都可以放在一个方法或重写onDestroy中。
下面的例子,但如果你有时间,这是一个很好的教程
第一个是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;
}
}
然后你就有了一个完美的类来充当刀。对于上面的示例,用法是
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;
}
您是否正在尝试在完成时关闭数据库? 如果是,请尝试:
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;
}
每次都应该正确关闭数据库。如果您想知道为什么它没有关闭,我会调查捕获的异常是什么意思
顺便说一下,我会用null替换“newstring[]{“*”}”。
更新:好了,现在我明白问题了。不过,您可能需要重新构造您的类
TLDR:对我来说,理想的结局是两门课。一个是帮助你打开数据库。第二种方法是将SQLiteDatabase对象作为属性保存。您可以在创建此类(或创建用于打开数据库的方法)后立即打开连接并初始化DB对象。所有方法仅将db对象用于SCUD。然后,所有db对象关闭或分解都可以放在一个方法或重写onDestroy中。
下面的例子,但如果你有时间,这是一个很好的教程
第一个是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;
}
}
然后你就有了一个完美的类来充当刀。对于上面的示例,用法是
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;
}
是的,我认为有一个问题。您可以将“db”作为参数传递,然后调用方可以在使用光标时关闭它。是的,我认为存在问题。您可以将“db”作为参数传递,然后调用方可以在使用光标时将其关闭。谢谢,但问题是,关闭db后,光标变得无效。我更新了答案。它有点长,有点曲折,但这会帮助你解决问题。谢谢你的回答!您的解决方案解决了当用户可以获取dbHelper对象时的问题。但在我的例子中,用户无法获取dbHelper对象,因为查询是在content provider上进行的。所以,我不能期望用户关闭数据库。谢谢,但问题是关闭数据库后,光标变得无效。我更新了答案。它有点长,有点曲折,但这会帮助你解决问题。谢谢你的回答!您的解决方案解决了当用户可以获取dbHelper对象时的问题。但在我的例子中,用户无法获取dbHelper对象,因为查询是在content provider上进行的。所以,我不能期望用户关闭数据库。