【09.03.30】Android中使用C++程序读写Parcel的简单例子

2024-01-07 10:08

本文主要是介绍【09.03.30】Android中使用C++程序读写Parcel的简单例子,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

http://apps.hi.baidu.com/share/detail/31773728

Android中的Parcel类困惑了我好一段时间(当然现在也没把Parcel完全弄明白),查了一些资料也不知道它里面是以一种什么格式存储数据的。因为它对外提供的读写函数都没有提到具体一个读写函数到底是读写Parcel中的哪一块地址里的数据。比如网上有这么两段代码:

    public void writeToParcel(Parcel out) { //当前数据写入到Parcel中
        out.writeInt(left);
        out.writeInt(top);
        out.writeInt(right);
        out.writeInt(bottom);
    }

    public void readFromParcel(Parcel in) { //从Parcel中读取数据
        left = in.readInt();
        top = in.readInt();
        right = in.readInt();
        bottom = in.readInt();
    }
   
其中无论是读函数writeInt(),还是写函数readInt(),参数中都没有提及是往Parcel中的具体哪块地方写入left变量,又是从Parcel的哪块地方读出数值赋给right变量。后来看了一些源码,包括Parcel.h和Parcel.cpp。感觉Parcel可能类似一个一维的数据串,各种变量都可以往里面写(通过Parcel提供的针对各种变量的具体函数),有一个位置指针指向这个一维的数据串中的某个位置,这个位置就是默认的读写的位置。也就是说,如果现在调用读写函数,就是读写当前位置指针处的数据,读写结束后,把位置指针向后移动一块空间(跨越的长度正好是你上次调用读写函数读过或者写过数据的长度),继续准备对下一部分空间进行读写操作。

为了验证这个想法,编写了一段对Parcel进行读写的C++程序。由于对C++较为生疏,编写这个小程序花了一下午的时间,不过最后总算是通过了。现在把代码贴在下面:

/********************** 以下是 Parcel_test.cpp 程序 ****************************/
/*这里的文件扩展名应该是.cpp,也就是c++文件,如果此处用c写程序,扩展名为.c的话,加入#include <utils/Parcel.h>这句后可能将出现错误*/
#include <utils/Parcel.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
    using namespace android;/*这一行一开始没有加上,结果总是出错,提示Parcel、status_t、NO_ERROR都没有定义,郁闷了好久,心想在include中加入了utils/Parcel.h呀,而且在Android.mk中也加入了Parcel.h所在的库libutils。后来看了Android源代码才推测出了可能要加入这句*/
    status_t status;
    size_t parcel_position;
    int intp=987654;
    char charp='g';
    float floatp=3.14159;
    double doublep=12345.6789012;
    long longp=1234567890;
    char *stringp="this is my parcel test!";

    Parcel p;
    parcel_position = p.dataPosition();/*备份位置*/
    printf("当前Parcel的读写位置是:%d\n",parcel_position);
    /*************写int类型***************/
    status=p.writeInt32(intp);
    if (status==NO_ERROR)
        printf("write int type success!\n");
    else
        printf("write int type fail,the errno=%d\n",errno);
    /*************写char类型***************/
    status=p.writeInt32(charp);
    if (status==NO_ERROR)
        printf("write char type success!\n");
    else
        printf("write char type fail,the errno=%d\n",errno);
    /*************写Float类型***************/
    status=p.writeFloat(floatp);
    if (status==NO_ERROR)
        printf("write Float type success!\n");
    else
        printf("write Float type fail,the errno=%d\n",errno);
    /*************写Double类型***************/
    status=p.writeDouble(doublep);
    if (status==NO_ERROR)
        printf("write Double type success!\n");
    else
        printf("write Double type fail,the errno=%d\n",errno);
    /*************写long类型***************/
    status=p.writeInt64(longp);
    if (status==NO_ERROR)
        printf("write long type success!\n");
    else
        printf("write long type fail,the errno=%d\n",errno);
    /*************写String类型***************/
    status=p.writeCString(stringp);
    if (status==NO_ERROR)
        printf("write String type success!\n");
    else
        printf("write String type fail,the errno=%d\n",errno);
    /*************将parcel读写位置置回原位***************/
    p.setDataPosition(parcel_position);
    /*************读出变量***************/
    printf("读出的int类型变量为:%d\n",p.readInt32());
    printf("读出的char类型变量为:%c\n",(char)p.readInt32());
    printf("读出的Float类型变量为:%f\n",(float)p.readFloat());
    printf("读出的Double类型变量为:%f\n",(double)p.readDouble());
    printf("读出的long类型变量为:%ld\n",(long)p.readInt64());
    printf("读出的字符串为:%s\n",p.readCString());
}
/********************** 以上是 Parcel_test.cpp 程序 ****************************/


/***************下面是对应的makefile文件******************/
/********************** 以下是Android.mk文件 ****************************/
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
    parcel_test.cpp

LOCAL_SHARED_LIBRARIES := \
    libutils \
    libcutils

LOCAL_CFLAGS :=

LOCAL_MODULE:= parcel_test

include $(BUILD_EXECUTABLE)
/********************** 以上是Android.mk文件 ****************************/

把这两个文件放在Android源码目录下的development目录下的parcel_test文件夹中(dl文件夹是新建的),然后在终端中使用root权限进入到Android源码目录下,执行 make parcel_test。成功后将会在android源码目录/out/target/product/generic/system/bin/中生成parcel_test可执行文件。

使用以下命令将它们放入Android模拟器,注意要先启动emulator

adb push Android源码目录/out/target/product/generic/system/bin/parcel_test /data

进入data文件夹执行
adb shell
# cd data
# ./parcel_test
// 以下是程序运行结果 //
当前Parcel的读写位置是:0
write int type success!
write char type success!
write Float type success!
write Double type success!
write long type success!
write String type success!
读出的int类型变量为:987654
读出的char类型变量为:g
读出的Float类型变量为:3.141590
读出的Double类型变量为:12345.678901
读出的long类型变量为:1234567890
读出的字符串为:this is my parcel test!


==============================
由此可知,Parcel中数据的存储结构的确正如之前猜测的那样,它是一个数据串,有一个位置指针标志着它当前的读写位置。写入数据的时候可以遵从某种约定,按照某种顺序把数据依此写进去,读的时候再按照同样的顺序依此把数据读出来。估计应该也可以通过设置指针位置的函数跳过某些数据进行读取或写入,但我这里没有做实验。

另外,如果写完之后再读,那么读之前记得要把位置指针重新置为要读的数据开始的地方,因为之前写的时候数据指针已经移动过了。


这篇关于【09.03.30】Android中使用C++程序读写Parcel的简单例子的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/579560

相关文章

golang1.23版本之前 Timer Reset方法无法正确使用

《golang1.23版本之前TimerReset方法无法正确使用》在Go1.23之前,使用`time.Reset`函数时需要先调用`Stop`并明确从timer的channel中抽取出东西,以避... 目录golang1.23 之前 Reset ​到底有什么问题golang1.23 之前到底应该如何正确的

详解Vue如何使用xlsx库导出Excel文件

《详解Vue如何使用xlsx库导出Excel文件》第三方库xlsx提供了强大的功能来处理Excel文件,它可以简化导出Excel文件这个过程,本文将为大家详细介绍一下它的具体使用,需要的小伙伴可以了解... 目录1. 安装依赖2. 创建vue组件3. 解释代码在Vue.js项目中导出Excel文件,使用第三

Linux alias的三种使用场景方式

《Linuxalias的三种使用场景方式》文章介绍了Linux中`alias`命令的三种使用场景:临时别名、用户级别别名和系统级别别名,临时别名仅在当前终端有效,用户级别别名在当前用户下所有终端有效... 目录linux alias三种使用场景一次性适用于当前用户全局生效,所有用户都可调用删除总结Linux

java图像识别工具类(ImageRecognitionUtils)使用实例详解

《java图像识别工具类(ImageRecognitionUtils)使用实例详解》:本文主要介绍如何在Java中使用OpenCV进行图像识别,包括图像加载、预处理、分类、人脸检测和特征提取等步骤... 目录前言1. 图像识别的背景与作用2. 设计目标3. 项目依赖4. 设计与实现 ImageRecogni

python管理工具之conda安装部署及使用详解

《python管理工具之conda安装部署及使用详解》这篇文章详细介绍了如何安装和使用conda来管理Python环境,它涵盖了从安装部署、镜像源配置到具体的conda使用方法,包括创建、激活、安装包... 目录pytpshheraerUhon管理工具:conda部署+使用一、安装部署1、 下载2、 安装3

Mysql虚拟列的使用场景

《Mysql虚拟列的使用场景》MySQL虚拟列是一种在查询时动态生成的特殊列,它不占用存储空间,可以提高查询效率和数据处理便利性,本文给大家介绍Mysql虚拟列的相关知识,感兴趣的朋友一起看看吧... 目录1. 介绍mysql虚拟列1.1 定义和作用1.2 虚拟列与普通列的区别2. MySQL虚拟列的类型2

使用MongoDB进行数据存储的操作流程

《使用MongoDB进行数据存储的操作流程》在现代应用开发中,数据存储是一个至关重要的部分,随着数据量的增大和复杂性的增加,传统的关系型数据库有时难以应对高并发和大数据量的处理需求,MongoDB作为... 目录什么是MongoDB?MongoDB的优势使用MongoDB进行数据存储1. 安装MongoDB

关于@MapperScan和@ComponentScan的使用问题

《关于@MapperScan和@ComponentScan的使用问题》文章介绍了在使用`@MapperScan`和`@ComponentScan`时可能会遇到的包扫描冲突问题,并提供了解决方法,同时,... 目录@MapperScan和@ComponentScan的使用问题报错如下原因解决办法课外拓展总结@

mysql数据库分区的使用

《mysql数据库分区的使用》MySQL分区技术通过将大表分割成多个较小片段,提高查询性能、管理效率和数据存储效率,本文就来介绍一下mysql数据库分区的使用,感兴趣的可以了解一下... 目录【一】分区的基本概念【1】物理存储与逻辑分割【2】查询性能提升【3】数据管理与维护【4】扩展性与并行处理【二】分区的

使用Python实现在Word中添加或删除超链接

《使用Python实现在Word中添加或删除超链接》在Word文档中,超链接是一种将文本或图像连接到其他文档、网页或同一文档中不同部分的功能,本文将为大家介绍一下Python如何实现在Word中添加或... 在Word文档中,超链接是一种将文本或图像连接到其他文档、网页或同一文档中不同部分的功能。通过添加超