Android 中 parcelable 和 parcel 的关系及源码可以看这篇文章, 不在多做描述, 只是根据源码结合之前学到的写出一个简单的 Parcel
.
目录结构如下:
1. 定义 Native
方法
首先是先定义一个 ZParcel
, 并定义出主要的 Native
方法.
package com.aaatest.study003;
public class ZParcel {
static {
System.loadLibrary("study003");
}
//共享内存, 全局只会存在一个 ZParcel 实例
//这就是 ZParcel 对象实例的首地址.
//创建 ZParcel 对象时, 会返回这个地址, 每次操作 ZParcel 对象, 都需要传入 long 类型的值到 Native 层
//native 拿到这个值后, 进行强制转换为 ZParcel 对象. 进行下面的操作.
private long mNativePtr = 0L;
private ZParcel(long nativePtr){
this.mNativePtr = nativePtr;
mNativePtr = nativeCreate();
}
private static class MyObject {
private static ZParcel ZPARCEL = new ZParcel(0L);
}
public static ZParcel obtain() {
return MyObject.ZPARCEL;
}
public final void writeInt(int val){
nativeWriteInt(mNativePtr, val);
}
public final int readInt(){
return nativeReadInt(mNativePtr);
}
public final void setDataPosition(int pos) {
nativeSetDataPosition(mNativePtr, pos);
}
private native long nativeCreate(); //构建对象指针
private native void nativeWriteInt(long mNativePtr, int val); //写入
private native void nativeSetDataPosition(long mNativePtr, int pos); //设置标记位,方便读写
private native int nativeReadInt(long mNativePtr);//读取
}
2. 生成头文件
在src/main/java
文件夹下使用命令 javah com.aaatest.study003.ZParcel
, 接着将生成的 com_aaatest_study003_ZParcel.h
头文件放入 cpp
目录下.
下面代码是生成的头文件内容.
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include <string>
#include <android/log.h>
#include "ZParcel.h"
/* Header for class com_aaatest_study003_ZParcel */
#ifndef _Included_com_aaatest_study003_ZParcel
#define _Included_com_aaatest_study003_ZParcel
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_aaatest_study003_ZParcel
* Method: nativeCreate
* Signature: ()J
*/
JNIEXPORT jlong JNICALL Java_com_aaatest_study003_ZParcel_nativeCreate
(JNIEnv *, jobject);
/*
* Class: com_aaatest_study003_ZParcel
* Method: nativeWriteInt
* Signature: (JI)V
*/
JNIEXPORT void JNICALL Java_com_aaatest_study003_ZParcel_nativeWriteInt
(JNIEnv *, jobject, jlong, jint);
/*
* Class: com_aaatest_study003_ZParcel
* Method: nativeSetDataPosition
* Signature: (JI)V
*/
JNIEXPORT void JNICALL Java_com_aaatest_study003_ZParcel_nativeSetDataPosition
(JNIEnv *, jobject, jlong, jint);
/*
* Class: com_aaatest_study003_ZParcel
* Method: nativeReadInt
* Signature: (J)I
*/
JNIEXPORT jint JNICALL Java_com_aaatest_study003_ZParcel_nativeReadInt
(JNIEnv *, jobject, jlong);
#ifdef __cplusplus
}
#endif
#endif
3. 使用
接着在 Activity 中的一个按钮点击事件中使用.
binding.sampleText.setOnClickListener{
val zParcel = ZParcel.obtain()
zParcel.writeInt(10)
zParcel.writeInt(20)
zParcel.setDataPosition(0)
val num1 = zParcel.readInt()
val num2 = zParcel.readInt()
Log.e("TAG", "num1 = ${num1}, num2 = ${num2}")
}
}
4. 在 cpp
文件夹新建名为 ZParcel
的 C++
文件和头文件
在 ZParcel.h
头文件中定义方法
#include "jni.h"
#include <malloc.h>
#ifndef STUDY003_ZPARCEL_H
#define STUDY003_ZPARCEL_H
class ZParcel {
private:
//ZParcel 对象在共享内存的首地址.
char * mData = 0;
//ZParcel 对象内存地址的指针移动位置
int mDataPos = 0;
//操作指针移动
void changePos(int pos);
public:
//构造
ZParcel();
//析构
virtual ~ZParcel();
//写
void writeInt(int val);
//设置指针位置
void setDataPosition(int pos);
//读
int readInt();
};
#endif //STUDY003_ZPARCEL_H
在 ZParcel.cpp
文件实现定义的方法
#include "ZParcel.h"
//构造函数
ZParcel::ZParcel() {
this->mData = static_cast<char *>(malloc(1024));
}
//析构函数, 释放
ZParcel::~ZParcel() {
if(this->mData) {
free(this->mData);
}
if(this->mDataPos) {
this->mDataPos = 0;
}
}
void ZParcel::writeInt(int val) {
//将要写的值赋值给 (ZParcel 在内存地址中的首地址 + 指针偏移的位置) 进行取值
//第一次写入 mDataPos = 0, 那就是从 ZParcel 首地址开始写入, 写入完成后, 指针移动. 变为 mDataPos = 4.
//第二次写入 mDataPos = 4, 那就是从 ZParcel 首地址向后偏移 4 位开始写入, 写入完成后, 指针移动, mDataPos = 8
//第三次 mDataPos = 8, ....偏移 8 位,........ mDataPos = 12.
* reinterpret_cast<int *>(this->mData + this->mDataPos) = val;
changePos(sizeof(int));
}
void ZParcel::changePos(int pos) {
this->mDataPos += pos;
}
int ZParcel::readInt() {
int ret = *reinterpret_cast<int *>(this->mData + this->mDataPos);
changePos(sizeof(int ));
return ret;
}
void ZParcel::setDataPosition(int pos) {
this->mDataPos = pos;
}
5. 编写 Native
方法
将在 javah com.aaatest.study003.ZParcel.h
头文件中生成的方法声明复制到 native-lib.cpp
中, 并实现.
extern "C"
JNIEXPORT jlong JNICALL Java_com_aaatest_study003_ZParcel_nativeCreate(JNIEnv * env, jobject job){
auto * zParcel = new ZParcel();
return reinterpret_cast<jlong>(zParcel);
}
extern "C"
JNIEXPORT void JNICALL Java_com_aaatest_study003_ZParcel_nativeWriteInt(JNIEnv * env, jobject , jlong zParcel, jint val){
auto * _zParcel = reinterpret_cast<ZParcel *>(zParcel);
_zParcel->writeInt(val);
}
extern "C"
JNIEXPORT void JNICALL Java_com_aaatest_study003_ZParcel_nativeSetDataPosition(JNIEnv * env, jobject , jlong zParcel, jint pos){
auto * _zParcel = reinterpret_cast<ZParcel *>(zParcel);
_zParcel->setDataPosition(pos);
}
extern "C"
JNIEXPORT jint JNICALL Java_com_aaatest_study003_ZParcel_nativeReadInt(JNIEnv * env, jobject , jlong zParcel){
auto * _zParcel = reinterpret_cast<ZParcel *>(zParcel);
return _zParcel->readInt();
}
6. 最后编辑 CMakeLists.txt
cmake_minimum_required(VERSION 3.18.1)
project("study003")
file(GLOB allSource *.c *.cpp)
add_library(
study003
SHARED
${allSource})
find_library(
log-lib
log)
target_link_libraries(
study003
${log-lib})
最后运行打印日志, 取值正确.