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})
最後運行打印日誌, 取值正確.