Android native CursorWindow数据保存原理
我们通过Uri查询数据库所得到的数据集,保存在native层的CursorWindow中。CursorWindow的实质是共享内存的抽象,以实现跨进程数据共享。共享内存所採用的实现方式是文件映射。
在ContentProvider端透过SQLiteDatabase的封装查询到的数据集保存在CursorWindow所指向的共享内存中。然后通过Binder把这片共享内存传递到ContentResolver端,即查询端。
这样客户就能够通过Cursor来訪问这块共享内存中的数据集了。
那么CursorWindow是怎样实现的呢?
1.通过Create静态函数来创建
status_t CursorWindow::create(const String8& name, size_t size, CursorWindow** outCursorWindow) {
    String8 ashmemName("CursorWindow: ");
    ashmemName.append(name);//文件名称
    status_t result;
    int ashmemFd = ashmem_create_region(ashmemName.string(), size);
    if (ashmemFd < 0) {
        result = -errno;
    } else {
        result = ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE);
        if (result >= 0) {
            void* data = ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0);//文件映射
            if (data == MAP_FAILED) {
                result = -errno;
            } else {
                result = ashmem_set_prot_region(ashmemFd, PROT_READ);
                if (result >= 0) {
                    CursorWindow* window = new CursorWindow(name, ashmemFd,
                            data, size, false /*readOnly*/);
                    result = window->clear();
                    if (!result) {
                        LOG_WINDOW("Created new CursorWindow: freeOffset=%d, "
                                "numRows=%d, numColumns=%d, mSize=%d, mData=%p",
                                window->mHeader->freeOffset,
                                window->mHeader->numRows,
                                window->mHeader->numColumns,
                                window->mSize, window->mData);
                        *outCursorWindow = window;
                        return OK;
                    }
                    delete window;
                }
            }
            ::munmap(data, size);
        }
        ::close(ashmemFd);
    }
    *outCursorWindow = NULL;
    return result;
}
2.通过文件句柄来创建。这样的case应该是在client的创建出一个CursorWindow所採用。
status_t CursorWindow::createFromParcel(Parcel* parcel, CursorWindow** outCursorWindow) {
    String8 name = parcel->readString8();
    status_t result;
    int ashmemFd = parcel->readFileDescriptor();
    if (ashmemFd == int(BAD_TYPE)) {
        result = BAD_TYPE;
    } else {
        ssize_t size = ashmem_get_size_region(ashmemFd);
        if (size < 0) {
            result = UNKNOWN_ERROR;
        } else {
            int dupAshmemFd = ::dup(ashmemFd);
            if (dupAshmemFd < 0) {
                result = -errno;
            } else {
                void* data = ::mmap(NULL, size, PROT_READ, MAP_SHARED, dupAshmemFd, 0);
                if (data == MAP_FAILED) {
                    result = -errno;
                } else {
                    CursorWindow* window = new CursorWindow(name, dupAshmemFd,
                            data, size, true /*readOnly*/);
                    LOG_WINDOW("Created CursorWindow from parcel: freeOffset=%d, "
                            "numRows=%d, numColumns=%d, mSize=%d, mData=%p",
                            window->mHeader->freeOffset,
                            window->mHeader->numRows,
                            window->mHeader->numColumns,
                            window->mSize, window->mData);
                    *outCursorWindow = window;
                    return OK;
                }
                ::close(dupAshmemFd);
            }
        }
    }
    *outCursorWindow = NULL;
    return result;
}
CursorWindow是怎样保存查询到的数据集的呢?
原理图例如以下:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvU2FpbGluZ3RoaW5r/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
没一行所相应的数据採用FieldSlot数组来表示。
图中黄色部分表示一行所相应的数据。假设列所相应的数据是long或者double。那么就直接保存在FieldSlot中,假设是Blob或者String,那么就在FieldSlot中保存数据的廉价量。
FiledSlot的定义例如以下:
    struct FieldSlot {
    private:
        int32_t type;//列所相应的数据的类型
        union {
            double d;
            int64_t l;
            struct {
                uint32_t offset;
                uint32_t size;
            } buffer;
        } data;//data的数据类型是union,当type所表示的是String或者Blob的时候。offset表示的就是保存真实数据的buffer的偏移量。size表示buffer的大小
        friend class CursorWindow;
    } __attribute((packed));
Android native CursorWindow数据保存原理的更多相关文章
- [原理] Android Native内存泄漏检测原理解析
		转载请注明出处:https://www.cnblogs.com/zzcperf/articles/11615655.html 上一篇文章列举了不同版本Android OS内存泄漏的检测操作(传送门), ... 
- Android中的数据保存
		形式 Android的数据保存分为3种形式:file, SharedPreference, Database 文件 主要思想就是通过Context类中提供的openFileInput和openFile ... 
- React-Native系列Android——Native与Javascript通信原理(一)
		React-Native最核心的是Native与Javascript之间的通信,并且是双向通信.Native层到Javascript层,Javascript层到Native层.虽说是两个方向,但实现上 ... 
- android中Json数据保存方式
		package com.example.savejsonproject; import java.io.File; import java.io.FileNotFoundException; impo ... 
- Android数据保存之SharedPreference
		前言: 程序中处理的大部分问题都与数据有关,读取数据显示在UI上,读取的数据可以是本地的,也可以是网络的.保存用户数据到存储空间,可以是本地的数据库,文件等,也可以是保存到网络服务器.总之大部分的程序 ... 
- Android应用程序组件Content Provider在应用程序之间共享数据的原理分析
		文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6967204 在Android系统中,不同的应用 ... 
- Android Native -- Message/Handler/Looper机制(原理篇)
		⌈Android Native消息队列处理系列文章⌋ Android Native -- Message/Handler/Looper机制(原理篇) Android Native -- Message ... 
- Android少量数据保存之SharedPreferences接口实例
		SharedPreferences数据保存主要是通过键值的方式存储在xml文件中 xml文件在data/此程序的包名/XX.xml 格式 <?xml version='1.0' encoding ... 
- Android数据存储(1)少量数据保存之SharedPreferences接口实例
		SharedPreferences数据保存主要是通过键值的方式存储在xml文件中 xml文件在data/此程序的包名/XX.xml 格式 <?xml version='1.0' encoding ... 
随机推荐
- 【数字图像处理】六.MFC空间几何变换之图像平移、镜像、旋转、缩放具体解释
			本文主要讲述基于VC++6.0 MFC图像处理的应用知识,主要结合自己大三所学课程<数字图像处理>及课件进行解说,主要通过MFC单文档视图实现显示BMP图片空间几何变换.包含图像平移.图形 ... 
- 终端安全工具 gartner 排名
			Reviews for Endpoint Detection and Response Solutions What is Endpoint Detection and Response Soluti ... 
- 【IOI 2011】Race
			[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=2599 [算法] 点分治 [代码] #include<bits/stdc++.h ... 
- webrtc所有平台下载编译步骤详细说明
			webrtc所有平台下载编译步骤详细说明 1.安装depot tools Windows:国外下载:https://storage.googleapis.com/chrome-infra/depot_ ... 
- Vmware 安装samba之二
			安装samba:sudo apt-get install samba 安装smbclient:sudo apt-get install 安装smbfs:sudo apt-get smbfs 2.修改配 ... 
- CentOS 7 NAT模式上网配置
			一 VMware 配置 在“编辑”选项卡中,选择“虚拟网络编辑器”,如下图: 选择VMnet8,修改子网IP与子网掩码,注意不要给“使用本地DHCP服务将IP地址分配给虚拟机”选项打勾,如下图: 点击 ... 
- EF Code First 使用 代码优先迁移(二)
			第一步:如果不是建立的MVC项目,可能需要在控制台输入 :Install-Package EntityFramework 删除之后在执行Enable-Migrations 第二步:添加你需要修改的属性 ... 
- vue中通过js控制页面样式方法
			在使用vue.js框架的时候,有时候会希望在页面渲染完成之后,再执行函数方法来处理初始化相关的操作,如果只处理页面位置.宽或者高时,必须要在页面完全渲染之后才可以,页面没有加载完成之前,获取到的宽高不 ... 
- js从数组中取出n个不重复的数据
			/** * 首先,针对这个数组做一个去重处理,避免你在后面取数据的时候,因为取到相同的元素而又要多去取一次随机数 * 将获取到的不重复的数组,再到这里样本里面去取随机数 * 每取到一次,就将这个元素从 ... 
- RecycleView错误: java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder
			1.错误 java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positi ... 
