Activity 里面提供了一个 managedQuery() 方法,按照 Android SDK 里面的说明,“the activity will manage its lifecycle for you.” 听起来很好,Activity 可以替你管理 Cursor 的生命周期了,就不用记着去 close() 了,代码可以更简洁。

但是 Activity 是怎么去管理 Cursor 的生命周期的呢?SDK 文档没说。最近遇到一个 bug,在一个 Activity 中,用 managedQuery() 查询数据库,将查询得到的 Cursor 用 CursorAdapter 与 ListView 绑定。然后在 Activity 里面执行批量删除数据表记录操作,因为耗时比较长,所以用了多线程处理。测试团队发现的 bug 是,在删除操作进行过程中,如果按下 Home 键,应用就崩溃了。崩溃原因是 Cursor 被释放了,导致工作线程的删除操作异常。

看了 Activity.java 的源码之后就明白为什么会崩溃了。managedQuery() 其实无非就是把查询得到的 Cursor 放到了 Activity 类的一个数组成员变量中,然后当 Activity stop 的时候,将这个数组里的每个 cursor 都关掉,以及在 resume 的时候,将数组里的每个 cursor 都重新查询一次。所以在按下 Home 键之后,Activity 被 stop 了,cursor 也就被关闭了,如果有个线程还在继续使用这个 cursor,就会抛异常了。

因此,在用 managedQuery() 的时候,需要清楚 cursor 什么时候会被释放,并考虑好自己的代码在 cursor 被释放后不再需要使用这个 cursor.

在Activity中为什么要用managedQuery()

刚开始接触android的时候,每次用数据库都会犹豫使用哪种方式,一种是getContentResolver().query(...),另一种是managedQuery(...),后来习惯了使用前一种,后一种就被我遗忘了,但是在实际做项目时,有时数据库经常会报cursor not close的warning,有的cursor你可以手动关闭,但是有一些就不可以了,比如当前是个listActivity,他的adapter是个cursorAdapter,这里的cursor就不能关掉,当然你可以在onDestroy中做关闭的操作,可是我比较习惯把cursor定义为局部变量,不是全局可见的,这样的话你就不能在onDestroy中关闭了。

后来就查看源代码,发现manageQuery可以为你维护这个cursor。在你退出activity时为你自动关闭,其实他的原理也很简单,看源码:

Activity.java

private static final class ManagedCursor {
ManagedCursor(Cursor cursor) {
mCursor = cursor;
mReleased = false;
mUpdated = false;
}

private final Cursor mCursor;
private boolean mReleased;
private boolean mUpdated;
}
private final ArrayList<ManagedCursor> mManagedCursors =
new ArrayList<ManagedCursor>();

这里定义了一个Cursor队列,这个Cursor是被封装的。

下面是对这个队列的操作:

public final Cursor managedQuery(Uri uri,
String[] projection,
String selection,
String[] selectionArgs,
String sortOrder)
{
Cursor c = getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder);
if (c != null) {
startManagingCursor(c);
}
return c;
}

//添加,注意要加锁

 public void startManagingCursor(Cursor c) {
synchronized (mManagedCursors) {
mManagedCursors.add(new ManagedCursor(c));
}
}

//在这个activity结束的时候,会调用onDestroy,所以清理的工作应该在那里

protected void onDestroy() {
//省略。。。。

// close any cursors we are managing.
synchronized (mManagedCursors) {
int numCursors = mManagedCursors.size();
for (int i = 0; i < numCursors; i++) {
ManagedCursor c = mManagedCursors.get(i);
if (c != null) {
c.mCursor.close();
}
}
mManagedCursors.clear();
}

//省略。。。。

}

最近又看源码,发现可以不用managedQuery,可以用普通的query,然后运行 startManagingCursor(cursor),同样可以把cursor交给系统去管理,不用担心cursor没有close的情况了。

Android Query & managedQuery

今天说一下以下两种方式query数据:

Java代码

使用方法一:若将Cursor c1数据放入Adapter 中,如getView() 调用加载数据,需在此Adapter对应Activity生命周期中,对Cursor进行控制,尤其要注意c1.close()的处理,否则会在反复出现如下Exception.

Java代码
  1. E/Cursor ( 1384): Finalizing a Cursor that has not been deactivated or closed. database = /data/data/xx/databases/xx.db, table = xx, query = SELECT xx
  2. E/Cursor ( 1384): android.database.sqlite.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here
  3. E/Cursor ( 1384): at android.database.sqlite.SQLiteCursor.<init>(SQLiteCursor.java:210)
  4. E/Cursor ( 1384): at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:53)
  5. E/Cursor ( 1384): at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1345)
  6. E/Cursor ( 1384): at android.database.sqlite.SQLiteDatabase.queryWithFactory(SQLiteDatabase.java:1229)
  7. E/Cursor ( 1384): at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1184)
  8. E/Cursor ( 1384): at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1301)

使用方法二:Cursor c2 会随着Activity生命周期的变化,让Activity去控制c2的生命周期,所以不用太但心cursor是否被close,是否requery.

原文引用:Making the query

To query a content provider, you can use either the ContentResolver.query() method or the Activity.managedQuery() method. Both methods take the same set of arguments, and both return a Cursor object. However, managedQuery() causes the activity to manage the life cycle of the Cursor. A managed Cursor handles all of the niceties, such as unloading itself when the activity pauses, and requerying itself when the activity restarts. You can ask an Activity to begin managing an unmanaged Cursor object for you by calling Activity.startManagingCursor().

Android Query managedQuery相关推荐

  1. [ Android实战 ] android query: BufferQueue has been abandoned 问题解决

    [ Android实战 ] android query: BufferQueue has been abandoned 问题解决 背景 日志分析 参考资料 解决方案 源码分析 总结 尊重原创,转载请注 ...

  2. Android开发managedQuery方法过时如何解决

    今天在获取手机相册照片的时候用到了managedQuery,然后发现managedQuery过时了,如下图所示: 于是就百度了一下解决办法,其实也挺简单的.用getContentResolver(). ...

  3. android模糊检索_【android学习笔记】ormlite学习之模糊搜索like

    [目标]实现表中多个字段模糊搜索. [方法]ormlite like方法 :like(columnName,pattern)    使用%通配符来匹配,指定行数据,返回匹配到的结果 使用示范:mDao ...

  4. Android推特图片保存路径,从twitter获取个人资料图片图像使用解析推特登录为Android...

    我有这个问题我自己,从来没有找到一个很好的答案,所以你的代码让我看着办吧! 您正在提取的InputStream实际上是JSON格式(例如{"id":4646546,"na ...

  5. Android 手机自动化测试工具有哪几种?

    Android 手机自动化测试工具有哪几种? 3 条评论 分享 按投票排序按时间排序 28 个回答 78赞同 反对,不会显示你的姓名 知乎用户,https://github.com/truebit 孙 ...

  6. Android开发框架汇总

    自开发Android已有两年多,接触到很多优秀的框架.觉得很有必要汇总一下,以便日后查阅. 帖子以后还会更新,总有新奇发生嘛. 1,最初接触到的Android开发框架是afinal,这里贴一个给git ...

  7. Android UI 组件开源软件(一)

    Android显示GIF动画 GifView GifView 是一个为了解决android中现在没有直接显示gif的view,只能通过mediaplay来显示这个问题的项目,其用法和 ImageVie ...

  8. XMPP文件传输(XEP-0096协议说明)

    XMPP XEP-0096协议是XMPP中的文件传输协议.        关于文件传输,在xmpp协议中有不少协议可以实现,而XEP-0096协议是其中非常简单的一个协议.由于邮件被删,我的代码dem ...

  9. 各种jar下载 Jar File Download

    http://www.java2s.com/Code/Jar/a/Cataloga.htm 按照字母查找.比如A开头的: a / a 4 a2j 2 a3 43 aaa 2 aacdecoder 2 ...

最新文章

  1. 两大图像处理库Halcon和Opencv 的对比
  2. android5.0 广播失效,解决Android 8.0及以上系统接收不到广播的问题
  3. MATLAB-Direct access of structure fields returned by a function call is not allowed 的解决方法~
  4. linux7网卡配置vlan,centos7配置vlan,实现一个网卡两个地址的功能
  5. CodeForces - 1284B New Year and Ascent Sequence(乱搞)
  6. 巴巴运动网学习笔记(16-20)
  7. oauth2四种授权方式小结
  8. Flink入门训练--以New York City Taxi为例
  9. 被阿里带火的数据中台,不靠这三个阶段绝对失败
  10. Facebook 开源 Instagram 的Python 代码静态安全分析工具 Pysa
  11. 【刘润五分钟商学院】-163生存,还是灭亡,没有中间态
  12. 深度学习常用数据集汇总
  13. VS2010应用程序的打包与图标设置
  14. 算法笔记习题 7-1小节
  15. iOS设计模式四部曲(二) 结构型模式 内附Demo
  16. 菜鸟之如何让项目跑起来(适合小白看,不是小白的不要进来看了,浪费时间)
  17. python字符串的内部函数_「Python」字符串操作内置函数
  18. Docker多容器搭建LNMP
  19. 1970年计算的时间转日期
  20. H3C产品的默认密码是多少?

热门文章

  1. 【瑞模网】ue4 摩尔纹 远处模型闪烁问题
  2. 为什么会显示未找到服务器,为什么我点开始游戏他显示未找到服务器列表呢 – 手机爱问...
  3. 经不住似水流年,逃不过此间少年
  4. 商用机器人市场“群雄并起”,8岁的优地科技为何能成独角兽?
  5. 熔断器模式(CircuitBreaker)
  6. 开发支付宝小程序问题一:很抱歉,系统监测到你的支付宝账号有异常,入驻失败
  7. 四、训练SVM分类器(Python)(train_model.py)
  8. 最新版lumion8.0下载地址
  9. Redis常用命令,清空Redis缓存数据库
  10. ARM 仿真器种类与概念(JTAG、SWD、JLink、ULink、ST-Link)