Android开发笔记之:深入理解Cursor相关的性能问题
2023-06-13 09:14:54 时间
当数据库中存有大量数据的时候,用Cursor查询时要注意,有可能引发性能问题。数据库查询出来的Cursor都会由一个CursorWindow来进行数据管理,包括内存空间的申请和数据的填充。CursorWindow对Cursor中的内容大小有限制,限制为1024*1024也就是1M,换句话说Cursor中数据的大小不能超过1M,如果超过1M会引发如下的错误:
08-2305:48:31.838:DEBUG/Cursor(1805):skip_rowsrow149
08-2305:48:31.844:ERROR/CursorWindow(1805):needtogrow:mSize=1048576,size=11499,freeSpace()=7397,numRows=80
08-2305:48:31.844:ERROR/CursorWindow(1805):notgrowingsincetherearealready80row(s),maxsize1048576
08-2305:48:31.844:ERROR/Cursor(1805):Failedallocating11499bytesforblobat228,7
08-2305:48:31.849:DEBUG/Cursor(1805):finish_program_and_get_row_countrow12
08-2305:48:31.851:DEBUG/browser/BrowserBookmarkFoldersAdapter(1805):getView()-Position:149
08-2305:48:32.019:DEBUG/Cursor(1805):skip_rowsrow148
这表明CursorWindow中的空闲空间已经不足,已经在申请新的空间,但似乎申请失败。这个错误有时候会导致查询得到的Cursor为null,有时候不会引发太严重的问题。但是它会引起性能上的问题,不停的申请空间会占用大量的CPU时间,从而导致整个手机变卡。特别是在ListView或GridView中绑定的Cursor,会导致无法滑动,或者滑动变的十分的卡。用Android2.3的原生Browser,打开其中的历史记录,当有超过200条历史记录时,不停的滑动,特别是由下向上滑时会变的十分的卡,而对于其书签,如果条目超过100,且每个都有缩略图时,滑动会变得特别的卡,甚至都打不开,就是这个原因。
1.只查询需要的字段
这个特别重要,根据UI显示的需要,或者实际的需要查询需要的字段。就是一定要给ContentResolver.query(uri,projection)第二个参数PROJECTION,如果这个参数为null,那么就会查询表中所有的字段,那么当条数一增加Cursor的大小会增长很快。Browser中历史记录的原因就是它在query的时候查询了所有的字段,其数所库中保存了favicon和thumbnail二进制文件,因此当包含了这二个字段时,Cursor的容量很容易就达到了限制。
2.二进制文件不要存在数据库中
数据库仅适用于保存一些较短文字,整数,布尔,浮点数等一些,易于查询和操作的轻量级的数据,目的也是在于快速搜索和查询。对于像图片,较长的文字(如文章)等大数据,最好直接以文件形式存储在硬盘中,然后在数据库保存它们的访问路径。对于像favicon这样的小图片也可以考虑存在数据库中,但是像对于thumbnail的图片就不明智,除非整个应用在数量上有限制(比如只有几十或百级)否则很容易在查询的时候达到1M的限制。
3.对于特别大量的数据超过5000级或万级或十万级或百万级的要分段查询
无论表中的一条记录数据量如何的小,当条数达到5000级或者万级或者更多的时候,还是会达到1M的限制,这时就需要分段查询,比如每次查询500个,或者1000个。另外,如果是要做展示用,这么多数据一下子出来,用户也不方便查看。
【实例】Android2.3书签,历史记录和最多访问三个页面当数据量达到300左右时,就会出现滑动很卡的现象,特别是由下向上滑动时,特别的卡,会狂打出:
08-2305:48:31.844:ERROR/CursorWindow(1805):needtogrow:mSize=1048576,size=11499,freeSpace()=7397,numRows=80
08-2305:48:31.844:ERROR/CursorWindow(1805):notgrowingsincetherearealready80row(s),maxsize1048576
08-2305:48:31.844:ERROR/Cursor(1805):Failedallocating11499bytesforblobat228,7
这样的LOG。而书签似乎都没有办法打开和滑动,其特别的卡。
究其原因就是它们在查询的时候都用了同一个字段集Browser.HISTORY_PROJECTION这个是把bookmarks表中的所有字段都查询出来。书签,历史记录和最多访问虽是三个不同的展示页,但它们的数据是相同的都是来自bookmarks表。Bookmarks表中存有_id,title,url,bookmark,favicon,touch_icon,thumbnail等字段,其中favicon和thumbnail是二进制图片数据(byte[])。Browser.HISTORY_PROJECTION里面包含了所有的字段,当然也包含了favicon和thumbnail,所以当条目一旦达到200多时,Cursor就会达到其1M的限制,因此会导致性能下降,滑动变卡。
事实上对于历史记录和最多访问二个页面来讲thumbnail和touch_icon根本就没有用到,它只需要_id,title,url,bookmark和favicon;对于书签页,也仅是在GRID时才用到thumbnail。所以,只需要把查询时的字段集Browser.HISTORY_PROJECTION中的THUMBNAIL去掉,即可以解决滑动变卡。
相关文章
- android 空间分享到朋友圈,Android开发之微信分享到好友,朋友圈
- android开发笔记之 Android代码混淆打包
- android onresume方法,Android onActivityResult()和onResume()的执行顺序
- strictmode android,(十三)Android 性能优化 StrictMode
- android singleTask
- android短信验证码代码,Android短信验证码自动填写实现代码
- eclipse中android开发_Android开发教程
- Android平台GB28181设备接入端如何支持跨网段语音对讲?
- Android 实现radiobutton单选换行效果
- Android OpenGL ES 基础原理
- 【Android 应用开发】Android之Bluetooth编程
- 【IOC 控制反转】Android 事件依赖注入 ( 事件依赖注入具体的操作细节 | 创建 事件监听器 对应的 动态代理 | 动态代理的数据准备 | 创建调用处理程序 | 创建动态代理实例对象 )
- 【Android 命令行工具】Android 命令行工具简介 ( 官方文档 | SDK 命令行工具 | SDK 构建工具 | SDK 平台工具 | 模拟器工具 | Jetifier 工具 )
- 【ijkplayer】编译 Android 版本的 ijkplayer ② ( 切换到 k0.8.8 分支 | 执行 init-android.sh 脚本进行初始化操作 )
- 【ijkplayer】编译 Android 版本的 ijkplayer ⑥ ( 进入 ijkplayer-android/android 目录 | 执行 compile-ijk.sh 脚本完成编译 )
- 【Android UI】Paint Gradient 渐变渲染 ③ ( RadialGradient 环形渐变渲染 | 在给定中心和半径的情况下绘制径向渐变的着色器 | 水波纹效果 )
- Android性能优化-内存泄漏的8个Case详解手机开发
- Android分页查询获取系统联系人信息详解编程语言
- Android系统与Linux之间的联系(android和linux)
- android实现获取正在运行的应用程序
- Android基础之Fragment与Activity交互详解
- android在异步任务中关闭Cursor的代码方法
- Android中扫描多媒体文件操作详解