Android native CursorWindow数据保存原理

转自http://blog.csdn.net/ifloveelse/article/details/28394103



我们通过Uri查询数据库所得到的数据集,保存在native层的CursorWindow中。CursorWindow的实质是共享内存的抽象,以实现跨进程数据共享。共享内存所采用的实现方式是文件映射。

在ContentProvider端透过SQLiteDatabase的封装查询到的数据集保存在CursorWindow所指向的共享内存中,然后通过Binder把这片共享内存传递到ContentResolver端,即查询端。这样客户就可以通过Cursor来访问这块共享内存中的数据集了。

那么CursorWindow是如何实现的呢?

1.通过Create静态函数来创建

  1. status_t CursorWindow::create(const String8& name, size_t size, CursorWindow** outCursorWindow) {  
  2.     String8 ashmemName("CursorWindow: ");  
  3.     ashmemName.append(name);//文件名  
  4.   
  5.     status_t result;  
  6.     int ashmemFd = ashmem_create_region(ashmemName.string(), size);  
  7.     if (ashmemFd < 0) {  
  8.         result = -errno;  
  9.     } else {  
  10.         result = ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE);  
  11.         if (result >= 0) {  
  12.             void* data = ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0);//文件映射  
  13.             if (data == MAP_FAILED) {  
  14.                 result = -errno;  
  15.             } else {  
  16.                 result = ashmem_set_prot_region(ashmemFd, PROT_READ);  
  17.                 if (result >= 0) {  
  18.                     CursorWindow* window = new CursorWindow(name, ashmemFd,  
  19.                             data, size, false /*readOnly*/);  
  20.                     result = window->clear();  
  21.                     if (!result) {  
  22.                         LOG_WINDOW("Created new CursorWindow: freeOffset=%d, "  
  23.                                 "numRows=%d, numColumns=%d, mSize=%d, mData=%p",  
  24.                                 window->mHeader->freeOffset,  
  25.                                 window->mHeader->numRows,  
  26.                                 window->mHeader->numColumns,  
  27.                                 window->mSize, window->mData);  
  28.                         *outCursorWindow = window;  
  29.                         return OK;  
  30.                     }  
  31.                     delete window;  
  32.                 }  
  33.             }  
  34.             ::munmap(data, size);  
  35.         }  
  36.         ::close(ashmemFd);  
  37.     }  
  38.     *outCursorWindow = NULL;  
  39.     return result;  
  40. }  

2.通过文件句柄来创建。这种case应该是在客户端的创建出一个CursorWindow所采用。

  1. status_t CursorWindow::createFromParcel(Parcel* parcel, CursorWindow** outCursorWindow) {  
  2.     String8 name = parcel->readString8();  
  3.   
  4.     status_t result;  
  5.     int ashmemFd = parcel->readFileDescriptor();  
  6.     if (ashmemFd == int(BAD_TYPE)) {  
  7.         result = BAD_TYPE;  
  8.     } else {  
  9.         ssize_t size = ashmem_get_size_region(ashmemFd);  
  10.         if (size < 0) {  
  11.             result = UNKNOWN_ERROR;  
  12.         } else {  
  13.             int dupAshmemFd = ::dup(ashmemFd);  
  14.             if (dupAshmemFd < 0) {  
  15.                 result = -errno;  
  16.             } else {  
  17.                 void* data = ::mmap(NULL, size, PROT_READ, MAP_SHARED, dupAshmemFd, 0);  
  18.                 if (data == MAP_FAILED) {  
  19.                     result = -errno;  
  20.                 } else {  
  21.                     CursorWindow* window = new CursorWindow(name, dupAshmemFd,  
  22.                             data, size, true /*readOnly*/);  
  23.                     LOG_WINDOW("Created CursorWindow from parcel: freeOffset=%d, "  
  24.                             "numRows=%d, numColumns=%d, mSize=%d, mData=%p",  
  25.                             window->mHeader->freeOffset,  
  26.                             window->mHeader->numRows,  
  27.                             window->mHeader->numColumns,  
  28.                             window->mSize, window->mData);  
  29.                     *outCursorWindow = window;  
  30.                     return OK;  
  31.                 }  
  32.                 ::close(dupAshmemFd);  
  33.             }  
  34.         }  
  35.     }  
  36.     *outCursorWindow = NULL;  
  37.     return result;  
  38. }  

CursorWindow是如何保存查询到的数据集的呢?

原理图如下:

没一行所对应的数据采用FieldSlot数组来表示。图中黄色部分表示一行所对应的数据。如果列所对应的数据是long或者double,那么就直接保存在FieldSlot中,如果是Blob或者String,那么就在FieldSlot中保存数据的便宜量。

FiledSlot的定义如下:

  1. struct FieldSlot {  
  2. private:  
  3.     int32_t type;//列所对应的数据的类型  
  4.     union {  
  5.         double d;  
  6.         int64_t l;  
  7.         struct {  
  8.             uint32_t offset;  
  9.             uint32_t size;  
  10.         } buffer;  
  11.     } data;//data的数据类型是union,当type所表示的是String或者Blob的时候,offset表示的就是保存真实数据的buffer的偏移量,size表示buffer的大小  
  12.   
  13.     friend class CursorWindow;  
  14. } __attribute((packed)); 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值