从源码看Android中sqlite是怎么读DB的(转)

简介: 执行query 执行SQLiteDatabase类中query系列函数时,只会构造查询信息,不会执行查询。 (query的源码追踪路径) 执行move(里面的fillwindow是真正打开文件句柄并分配内存的地方) 当执行Cursor的move系列函数时,第一次执行,会为查询结果集创建一...

执行query

执行SQLiteDatabase类中query系列函数时,只会构造查询信息,不会执行查询。

(query的源码追踪路径)

执行move(里面的fillwindow是真正打开文件句柄并分配内存的地方)

当执行Cursor的move系列函数时,第一次执行,会为查询结果集创建一块共享内存,即cursorwindow

moveToPosition源码路径

 

fillWindow----真正耗时的地方

然后会执行sql语句,向共享内存中填入数据,

fillWindow源码路径

在SQLiteCursor.java中可以看到

复制代码
 1 @Override
 2 public boolean onMove(int oldPosition, int newPosition) {  3 // Make sure the row at newPosition is present in the window  4 if (mWindow == null || newPosition < mWindow.getStartPosition() ||  5 newPosition >= (mWindow.getStartPosition() + mWindow.getNumRows())) {  6  fillWindow(newPosition);  7  }  8  9 return true; 10 }
复制代码

 

如果请求查询的位置在cursorWindow的范围内,不会执行fillWindow,

而超出cursorwindow的范围,会调用fillWindow,

而在nativeExecuteForCursorWindow中,

获取记录时,如果要请求的位置超出窗口范围,会发生CursorWindow的清空:

复制代码
 1 CopyRowResult cpr = copyRow(env, window, statement, numColumns, startPos, addedRows);  
 2 if (cpr == CPR_FULL && addedRows && startPos + addedRows < requiredPos) {  
 3 // We filled the window before we got to the one row that we really wanted.  4 // Clear the window and start filling it again from here.  5 // TODO: Would be nicer if we could progressively replace earlier rows.  6 window->clear();  7 window->setNumColumns(numColumns);  8 startPos += addedRows;  9 addedRows = 0; 10 cpr = copyRow(env, window, statement, numColumns, startPos, addedRows); 11 } 
复制代码

 

CursorWindow的清空机制会影响到多线程读(通常认为不可以并发读写,sqlite的并发实际上是串行执行的,但可以并发读,这里要强调的是多线程读也可能有问题),具体见稍后一篇文章“listview并发读写数据库”。

 

Cursor关闭(显式调用close()的理由)

追踪源码看关闭

 1  //SQLiteCursor
 2 
 3 super.close();  4 synchronized (this) {  5  mQuery.close();  6  mDriver.cursorClosed();  7 }  8  9 10 //AbstractCursor 11 12 public void close() { 13 mClosed = true; 14  mContentObservable.unregisterAll(); 15  onDeactivateOrClose(); 16 } 17 18 protected void onDeactivateOrClose() { 19 if (mSelfObserver != null) { 20  mContentResolver.unregisterContentObserver(mSelfObserver); 21 mSelfObserverRegistered = false; 22  } 23  mDataSetObservable.notifyInvalidated(); 24 } 25 26 27 //AbstractWindowedCursor 28 29 /** @hide */ 30 @Override 31 protected void onDeactivateOrClose() { 32 super.onDeactivateOrClose(); 33  closeWindow(); 34 } 35 36 protected void closeWindow() { 37 if (mWindow != null) { 38  mWindow.close(); 39 mWindow = null; 40  } 41 } 42 43 44 45 //SQLiteClosable 46 47 public void close() { 48  releaseReference(); 49 } 50 51 public void releaseReference() { 52 boolean refCountIsZero = false; 53 synchronized(this) { 54 refCountIsZero = --mReferenceCount == 0; 55  } 56 if (refCountIsZero) { 57  onAllReferencesReleased(); 58  } 59 } 60 61 //CursorWindow 62 63 @Override 64 protected void onAllReferencesReleased() { 65  dispose(); 66 } 67 68 private void dispose() { 69 if (mCloseGuard != null) { 70  mCloseGuard.close(); 71  } 72 if (mWindowPtr != 0) { 73  recordClosingOfWindow(mWindowPtr); 74  nativeDispose(mWindowPtr); 75 mWindowPtr = 0; 76  } 77 }
View Code

 

跟CursorWindow有关的路径里,最终调用nativeDispose()清空cursorWindow;

当Cursor被GC回收时,会调用finalize:

复制代码
 1 @Override
 2 protected void finalize() {  3 try {  4 // if the cursor hasn't been closed yet, close it first  5 if (mWindow != null) {  6 if (mStackTrace != null) {  7 String sql = mQuery.getSql();  8 int len = sql.length();  9  StrictMode.onSqliteObjectLeaked( 10 "Finalizing a Cursor that has not been deactivated or closed. " + 11 "database = " + mQuery.getDatabase().getLabel() + 12 ", table = " + mEditTable + 13 ", query = " + sql.substring(0, (len > 1000) ? 1000 : len), 14  mStackTrace); 15  } 16  close(); 17  } 18 } finally { 19 super.finalize(); 20  } 21 }
复制代码

 

然而finalize()并没有释放CursorWindow,而super.finalize();里也只是解绑了观察者,没有去释放cursorwindow

所以不调用cursor.close(),最终会导致cursorWindow所在的共享内存(1M或2M)泄露。

http://www.cnblogs.com/hellocwh/p/4924732.html

 

相关文章
|
6月前
|
XML 搜索推荐 Android开发
Android改变进度条控件progressbar的样式(根据源码修改)
本文介绍了如何基于Android源码自定义ProgressBar样式。首先分析了系统源码中ProgressBar样式的定义,发现其依赖一张旋转图片实现动画效果。接着分两步指导开发者实现自定义:1) 模仿源码创建一个旋转动画XML文件(放置在drawable文件夹),修改图片为自定义样式;2) 在UI控件中通过`indeterminateDrawable`属性应用该动画。最终实现简单且个性化的ProgressBar效果,附带效果图展示。
432 2
|
7月前
|
NoSQL 应用服务中间件 PHP
布谷一对一直播源码android版环境配置流程及功能明细
部署需基于 CentOS 7.9 系统,硬盘不低于 40G,使用宝塔面板安装环境,包括 PHP 7.3(含 Redis、Fileinfo 扩展)、Nginx、MySQL 5.6、Redis 和最新 Composer。Swoole 扩展需按步骤配置。2021.08.05 后部署需将站点目录设为 public 并用 ThinkPHP 伪静态。开发环境建议 Windows 操作系统与最新 Android Studio,基础配置涉及 APP 名称修改、接口域名更换、包名调整及第三方登录分享(如 QQ、微信)的配置,同时需完成阿里云与腾讯云相关设置。
|
Ubuntu 开发工具 Android开发
Repo下载AOSP源码:基于ubuntu22.04 环境配置,android-12.0.0_r32
本文介绍了在基于Ubuntu 22.04的环境下配置Python 3.9、安装repo工具、下载和同步AOSP源码包以及处理repo同步错误的详细步骤。
1215 0
Repo下载AOSP源码:基于ubuntu22.04 环境配置,android-12.0.0_r32
|
开发工具 git 索引
repo sync 更新源码 android-12.0.0_r34, fatal: 不能重置索引文件至版本 ‘v2.27^0‘。
本文描述了在更新AOSP 12源码时遇到的repo同步错误,并提供了通过手动git pull更新repo工具来解决这一问题的方法。
571 1
|
Android开发 Docker 容器
docker中编译android aosp源码,出现Build sandboxing disabled due to nsjail error
在使用Docker编译Android AOSP源码时,如果遇到"Build sandboxing disabled due to nsjail error"的错误,可以通过在docker run命令中添加`--privileged`参数来解决权限不足的问题。
2479 1
|
开发工具 uml git
AOSP源码下载方法,解决repo sync错误:android-13.0.0_r82
本文分享了下载AOSP源码的方法,包括如何使用repo工具和处理常见的repo sync错误,以及配置Python环境以确保顺利同步特定版本的AOSP代码。
2332 0
AOSP源码下载方法,解决repo sync错误:android-13.0.0_r82
|
Java Android开发 芯片
使用Android Studio导入Android源码:基于全志H713 AOSP,方便解决编译、编码问题
本文介绍了如何将基于全志H713芯片的AOSP Android源码导入Android Studio以解决编译和编码问题,通过操作步骤的详细说明,展示了在Android Studio中利用代码提示和补全功能快速定位并修复编译错误的方法。
1146 0
使用Android Studio导入Android源码:基于全志H713 AOSP,方便解决编译、编码问题
|
Android开发
我的Android 进阶修炼(1): AOSP源码根目录结构
本文介绍了AOSP源码的根目录结构,提供了基于MTK9269 Android 9.0源码的目录说明,帮助读者了解AOSP源码的组织方式和各目录的功能。
973 0
我的Android 进阶修炼(1): AOSP源码根目录结构
|
开发工具 Android开发 git
全志H713 Android 11 :给AOSP源码,新增一个Product
本文介绍了在全志H713 Android 11平台上新增名为myboard的产品的步骤,包括创建新的device目录、编辑配置文件、新增内核配置、记录差异列表以及编译kernel和Android系统的详细过程。
1092 0
|
Ubuntu 开发工具 Android开发
Repo下载、编译AOSP源码:基于Ubuntu 21.04,android-12.1.0_r27
文章记录了作者在Ubuntu 21.04服务器上配置环境、下载并编译基于Android 12.1.0_r27版本的AOSP源码的过程,包括解决编译过程中遇到的问题和错误处理方法。
1092 0
下一篇
oss云网关配置