java - 在返回光标的函数中关闭光标
问题描述
在我的 SQLite 类中关闭 Cursor 时遇到问题。当我关闭 Cursor 并SQLiteDatabase
在 finally 块中 (in DBHelper
) 时,我无法读取其他类中的数据(无法重新打开已关闭的 Cursor 错误)但是当我不关闭 Cursor 时SQLiteDatabase
出现内存泄漏错误。
DHHelper.java:
//...
public Cursor selectData(String selectVal, String tabName){
SQLiteDatabase db = this.getReadableDatabase();
Cursor c = null;
try {
String areaTyp = "SELECT " + selectVal + " FROM " + tabName;
c = db.rawQuery(areaTyp, null);
return c;
} finally {
c.close();
db.close();
}
}
//...
用户管理器.java
public List<UserModel> getUsersList(){
List<UserModel> allUsers = new ArrayList<UserModel>();
final DBHelper db = new DBHelper(appStatic.CONTEX);
Cursor c = db.selectData("*","User");
if (c.moveToFirst()) {
while (!c.isAfterLast()) {
allUsers.add(new UserModel(c.getString(c.getColumnIndex("cms_id")),
c.getString(c.getColumnIndex("login")),
c.getString(c.getColumnIndex("name")),
c.getString(c.getColumnIndex("active")),
c.getString(c.getColumnIndex("avatar")),
c.getString(c.getColumnIndex("gtoken"))));
c.moveToNext();
}
}
c.close();
db.close();
return allUsers;
}
也许我应该以其他方式执行此操作,而返回 Cursor 的函数是个坏主意?
编辑: 当我运行应用程序时,我有错误:
java.lang.IllegalStateException:尝试重新打开一个已经关闭的对象:SQLiteQuery:SELECT * FROM User
在 UserMenager.java 中,行
if (c.moveToFirst()) {
解决方案
我建议从selectData
类中返回您想要的最终结果,即 ArrayList。然后,您可以在完成后立即关闭方法中的光标和数据库selectData
。
例如:-
public ArrayList<UserModel> selectData(String selectVal, String tabName){
SQLiteDatabase db = this.getWritableDatabase(); //<<<< getReadable will most likely return a writeable database anyway
ArrayList<UserModel> rv = new ArrayList<>();
Cursor c = db.query(
tabName,
new String[]{selectVal},
null,
null,
null,
null,
null
);
while (c.moveToNext()) {
rv.add(new UserModel(
c.getString(c.getColumnIndex("cms_id")),
c.getString(c.getColumnIndex("login")),
c.getString(c.getColumnIndex("name")),
c.getString(c.getColumnIndex("active")),
c.getString(c.getColumnIndex("avatar")),
c.getString(c.getColumnIndex("gtoken"))
));
}
c.close();
db.close();
return rv;
}
随着 :-
public List<UserModel> getUsersList(){
List<UserModel> allUsers = new ArrayList<UserModel>();
final DBHelper db = new DBHelper(appStatic.CONTEX);
return selectData("*","Users");
}
- 包裹
try
/catch
围绕 SQLiteDatabase 方法往往会导致更多的挫败感和混乱,而不是其他方式。 - 通常推荐使用便捷方法而不是使用
rawQuery
andexecSQL
方法(在这种情况下query
是便捷方法)。 - 理想情况下,selectVal应该是列的 String[] 而不仅仅是一个 String 以适应
query
方便的方法。 - 正如所评论的那样
getReadableDatabase
,很少获得只读数据库
- 创建和/或打开数据库。这将与 getWritableDatabase() 返回的对象相同,除非某些问题(例如磁盘已满)需要以只读方式打开数据库。在这种情况下,将返回一个只读数据库对象。如果问题得到解决,未来对 getWritableDatabase() 的调用可能会成功,在这种情况下,只读数据库对象将被关闭,并且将来会返回读/写对象。 SQLiteDatabase getReadableDatabase
推荐阅读
- odoo - 如何在 Odoo 13 网站中显示消息框
- nuget - Nuget List 命令不包括来自 Artifactory Nuget 存储库的所有结果
- python - Series 的第 n 项的总和
- kendo-ui - 使用带有锚点的 Kendo 弹出窗口 Angular
- javascript - 如何使用 ajv 模式验证验证值是否为格式和/或类型为 double?
- c++ - 如何让我的代码适用于较大的 N 值?
- java - PCB 类型中的方法 placeComponent() 不适用于参数(HardwareComponent)
- asp.net-mvc - 传递 htmlAttributes 时在 MVC 中使用 @Ajax.ActionLink 时出现问题
- html - 如何在 HTML 中添加多个引号?
- compiler-construction - 用于 Flex/Bison 的 API/库