Android Parcel应用要点
2016-08-17 18:29
771 查看
一,概念:
Parcel就是一个存放读取数据的容器,
Android系统中的binder进程间通信(IPC)就使用了Parcel类来进行客户端与服务端数据的交互,而且AIDL的数据也是通过Parcel来交互的。在Java空间和C++都实现了Parcel,由于它在C/C++中,直接使用了内存来读取数据,因此,它更有效率。他可以通过JNI来实现Java和C++的传输。
二,应用范围:
Parcel 的传送可以在Java 与Java之间,Java与JNI之间,C++(C)与JNI;C++(C)与C++(C)之间;如果需要从C和Java之间传输,需要从上面3个层次相续传输即可。
Java 之间参考:frameworks\base\core\java\android\os\ Parcel.java
Java与jni之间参考: frameworks\base\core\jni\ android_os_Parcel.cpp
c与jni之间或C之间参考: frameworks\native\libs\binder\ Parcel.cpp
三,java上的应用
创建:Parcel p = Parcel.obtain();
读数据:p.writeInt(cfg.mFreq);
读写偏移:p.setDataPosition(0);
写数据:int value = p.readInt();
销毁:p.recycle();
要点:因为读写遵循序列先后原则,读写必须按照其偏移位置来操作,否则会产生错乱。
四,JNI上的应用
因为无法直接在jave和JNI层操作内存,所以无法直接传输parcel的地址,需要转成jni的obj;传输给jave;
Jni的实现如下
/****获传递parcel jave的方法*******/
fields.post_event =env->GetStaticMethodID(clazz, "postEventFromNative",
"(Ljava/lang/Object;IIILjava/lang/Object;)V");
void JNIDvbListener::notify(intmsg, int ext1, int ext2, const Parcel *p_obj)
{
JNIEnv *env =AndroidRuntime::getJNIEnv();
//__android_log_print(ANDROID_LOG_ERROR,"dvbclientjni","notify");
if (p_obj &&p_obj->dataSize() > 0) {
#if 1
/**生成一个jnijava parcel OBJ**/
jobject jParcel = createJavaParcelObject(env);
if (jParcel != NULL)
{
Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
if(NULL != nativeParcel)
{
nativeParcel->setData(p_obj->data(),p_obj->dataSize());
nativeParcel->setDataPosition(0);
/*****调用JAVE 并传递Parcel obj ********/
env->CallStaticVoidMethod(mClass,
fields.post_event,mObject,
msg, ext1, ext2, jParcel);
/**销毁一个jni java parcel OBJ**/
env->DeleteLocalRef(jParcel);
}
}
}
Jave 对应接口如下:
private static void postEventFromNative(Object DvbClient_ref,
int what, int arg1, intarg2, Object obj)
{
if(obj instanceof Parcel){
try{
/***parcel obj 转换 ******/
Parcelparcel_obj = (Parcel)obj;
int parcel_size =parcel_obj.dataSize();
parcel_obj.setDataPosition(0);
int data_size =parcel_obj.readInt();
System.out.println("onDvbMessage:epg hava parcel data,size = "+String.valueOf(parcel_size)
+";data size ="+ String.valueOf(data_size)+"\n");
byte[]json_buffer = new byte[data_size];
parcel_obj.setDataPosition(0);
parcel_obj.readByteArray(json_buffer);
parcel_obj.recycle();
}
五,进程间通信(IPC)应用:
Bp
{
****************************
virtualstatus_t DvbServiceControl(int cmd, int data1, int data2, const Parcel *p_obj)
{
Parcel data, reply;
data.writeInterfaceToken(IDVBService::getInterfaceDescriptor());
data.writeInt32(cmd);
data.writeInt32(data1);
data.writeInt32(data2);
if (p_obj && p_obj->dataSize() > 0) {
data.appendFrom(const_cast<Parcel *>(p_obj), 0,p_obj->dataSize());
}
remote()->transact(DVB_SERVICE_CONTROL, data, &reply);
return reply.readInt32();
}
****************************
}
onTransact
{
****************************
CHECK_INTERFACE(IDVBService, data,reply);
case DVB_SERVICE_CONTROL:
{
int cmd =data.readInt32();
int data1 = data.readInt32();
int data2 = data.readInt32();
Parcel obj;
if (data.dataAvail() > 0) {
obj.appendFrom(const_cast<Parcel *>(&data),data.dataPosition(), data.dataAvail());
}
DvbServiceControl(cmd,data1,data2,&obj);
return(reply->writeInt32(NO_ERROR));
}
****************************
}
在bp 和transact中要保持读写一一对应关系。
六,数据块传输方式:
C到Java方式:
void DvbserviceSetNotify(intmsg_id, int data1, int data2,
void*p_data, int data_size)
{
// int i = 0;
unsigned char *p_parce_buff =(unsigned char *)p_data;
if(p_parce_buff != NULL)
{
Parcelmobj;
int parcel_size = 0;
/****长度必须保留四字节对齐*****/
parcel_size =ALIGN4_SIZE(d
4000
ata_size);
/****user java parcel readByteArray*******/
/****读取的方法,先读长度,建立数组,在设置偏移量到头,Java Array
读取方式内部会再读取长度来和数据比较*****/
mobj.writeInt32(parcel_size); /**
写数组长度,主要给Java Array
读取方式内部会再读取长度***/
mobj.write(p_parce_buff,parcel_size);
mobj.setDataPosition(0);
/****传输Java接口*****/
dvbclient->notify(msg_id,data1,data2,&mobj);
/****释放Parcelobj*****/
mobj.freeData();
}
}
Java 实现:
private static void postEventFromNative(Object DvbClient_ref,
int what, int arg1, intarg2, Object obj)
{
*************************
if(obj != null){
else if(objinstanceof Parcel){
try{
Parcel parcel_obj = (Parcel)obj;
int parcel_size = parcel_obj.dataSize();
parcel_obj.setDataPosition(0);
intdata_size = parcel_obj.readInt();
byte[]json_buffer = new byte[data_size];
/****读取的方法,先读长度,建立数组,在设置偏移量到头,Java Array
读取方式内部会再读取长度来和数据比较*****/
parcel_obj.setDataPosition(0);
parcel_obj.readByteArray(json_buffer);
/*
/****以下是顺序读写方式,不需要C语言写长度mobj.writeInt32(parcel_size);***/
intvalue = 0;
date_size = parcel_obj.dataSize();
for(inti = 0,j = 0;i < date_size;i += 4,j ++)
{
value= data.readInt();
json_buffer[i] = (byte)(value& 0xff);
json_buffer[i + 1] =(byte)((value>> 8) & 0xff);
json_buffer[i + 2] =(byte)((value >> 16) & 0xff);
json_buffer[i + 3] =(byte)((value >> 24) & 0xff);
}
*/
parcel_obj.recycle();
String json_str = newString(json_buffer);
*************************
}
Java到C的方式:
Java 使用接口不一样,JNI的读取方式也不一样
Parcel parcel_in = Parcel.obtain();
try
{
/* use write bye arraymode
int byte_size =pg_src.Ch_priv_data.length * 4;
byte[] Ch_byte_data =new byte[byte_size];
for(int i = 0; i <pg_src.Ch_priv_data.length;i ++)
{
int j = i * 4;
Ch_byte_data[j +3] = (byte)(pg_src.Ch_priv_data[i] >> 24);
Ch_byte_data[j +2] = (byte)(pg_src.Ch_priv_data[i] >> 16);
Ch_byte_data[j +1] = (byte)(pg_src.Ch_priv_data[i] >> 8);
Ch_byte_data[j] =(byte)(pg_src.Ch_priv_data[i]);
}
parcel_in.writeByteArray(Ch_byte_data);
*/
/*****以上使用的是writeByteArray接口*****/
parcel_in.writeIntArray(pg_src.Ch_priv_data);
/*****此次拥有的是writeIntArray *****/
parcel_in.recycle();
}
catch(Exception e)
{
e.printStackTrace();
}
JNI 对应接口如下:
{
Parcel *p_obj = parcelForJavaObject(env, java_obj);
if (p_obj &&p_obj->dataSize() > 0)
{
data_size =p_obj->dataSize();
/******parce 有效数据总的字节数*****/
p_data_buff = (int*)malloc(data_size + 4);
if(p_data_buff !=NULL)
{
p_obj->setDataPosition(0);
data_size =p_obj->readInt32();
/******parce 在java层写的Array类型个数,如果是writeByteArray 接口,那么就是byte的个数,如果是writeIntArray ,那么就是int 的个数*****/
#if 0 /***use write bye array mode**/
p_obj->read(p_data_buff,data_size);
/**** 直接读取buffer,必须对应javewriteByteArray 接口,且p_data_buff类型为unsigned char *类型*******/
#else
for(int i = 0;i< data_size;i ++)
{
p_data_buff[i]= p_obj->readInt32();
}
/****逐个读取int buffer,必须对应jave writeIntArray接口,且p_data_buff 类型为unsignedint *类型*******/
#endif
free(p_data_buff);
}
}
Parcel就是一个存放读取数据的容器,
Android系统中的binder进程间通信(IPC)就使用了Parcel类来进行客户端与服务端数据的交互,而且AIDL的数据也是通过Parcel来交互的。在Java空间和C++都实现了Parcel,由于它在C/C++中,直接使用了内存来读取数据,因此,它更有效率。他可以通过JNI来实现Java和C++的传输。
二,应用范围:
Parcel 的传送可以在Java 与Java之间,Java与JNI之间,C++(C)与JNI;C++(C)与C++(C)之间;如果需要从C和Java之间传输,需要从上面3个层次相续传输即可。
Java 之间参考:frameworks\base\core\java\android\os\ Parcel.java
Java与jni之间参考: frameworks\base\core\jni\ android_os_Parcel.cpp
c与jni之间或C之间参考: frameworks\native\libs\binder\ Parcel.cpp
三,java上的应用
创建:Parcel p = Parcel.obtain();
读数据:p.writeInt(cfg.mFreq);
读写偏移:p.setDataPosition(0);
写数据:int value = p.readInt();
销毁:p.recycle();
要点:因为读写遵循序列先后原则,读写必须按照其偏移位置来操作,否则会产生错乱。
四,JNI上的应用
因为无法直接在jave和JNI层操作内存,所以无法直接传输parcel的地址,需要转成jni的obj;传输给jave;
Jni的实现如下
/****获传递parcel jave的方法*******/
fields.post_event =env->GetStaticMethodID(clazz, "postEventFromNative",
"(Ljava/lang/Object;IIILjava/lang/Object;)V");
void JNIDvbListener::notify(intmsg, int ext1, int ext2, const Parcel *p_obj)
{
JNIEnv *env =AndroidRuntime::getJNIEnv();
//__android_log_print(ANDROID_LOG_ERROR,"dvbclientjni","notify");
if (p_obj &&p_obj->dataSize() > 0) {
#if 1
/**生成一个jnijava parcel OBJ**/
jobject jParcel = createJavaParcelObject(env);
if (jParcel != NULL)
{
Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
if(NULL != nativeParcel)
{
nativeParcel->setData(p_obj->data(),p_obj->dataSize());
nativeParcel->setDataPosition(0);
/*****调用JAVE 并传递Parcel obj ********/
env->CallStaticVoidMethod(mClass,
fields.post_event,mObject,
msg, ext1, ext2, jParcel);
/**销毁一个jni java parcel OBJ**/
env->DeleteLocalRef(jParcel);
}
}
}
Jave 对应接口如下:
private static void postEventFromNative(Object DvbClient_ref,
int what, int arg1, intarg2, Object obj)
{
if(obj instanceof Parcel){
try{
/***parcel obj 转换 ******/
Parcelparcel_obj = (Parcel)obj;
int parcel_size =parcel_obj.dataSize();
parcel_obj.setDataPosition(0);
int data_size =parcel_obj.readInt();
System.out.println("onDvbMessage:epg hava parcel data,size = "+String.valueOf(parcel_size)
+";data size ="+ String.valueOf(data_size)+"\n");
byte[]json_buffer = new byte[data_size];
parcel_obj.setDataPosition(0);
parcel_obj.readByteArray(json_buffer);
parcel_obj.recycle();
}
五,进程间通信(IPC)应用:
Bp
{
****************************
virtualstatus_t DvbServiceControl(int cmd, int data1, int data2, const Parcel *p_obj)
{
Parcel data, reply;
data.writeInterfaceToken(IDVBService::getInterfaceDescriptor());
data.writeInt32(cmd);
data.writeInt32(data1);
data.writeInt32(data2);
if (p_obj && p_obj->dataSize() > 0) {
data.appendFrom(const_cast<Parcel *>(p_obj), 0,p_obj->dataSize());
}
remote()->transact(DVB_SERVICE_CONTROL, data, &reply);
return reply.readInt32();
}
****************************
}
onTransact
{
****************************
CHECK_INTERFACE(IDVBService, data,reply);
case DVB_SERVICE_CONTROL:
{
int cmd =data.readInt32();
int data1 = data.readInt32();
int data2 = data.readInt32();
Parcel obj;
if (data.dataAvail() > 0) {
obj.appendFrom(const_cast<Parcel *>(&data),data.dataPosition(), data.dataAvail());
}
DvbServiceControl(cmd,data1,data2,&obj);
return(reply->writeInt32(NO_ERROR));
}
****************************
}
在bp 和transact中要保持读写一一对应关系。
六,数据块传输方式:
C到Java方式:
void DvbserviceSetNotify(intmsg_id, int data1, int data2,
void*p_data, int data_size)
{
// int i = 0;
unsigned char *p_parce_buff =(unsigned char *)p_data;
if(p_parce_buff != NULL)
{
Parcelmobj;
int parcel_size = 0;
/****长度必须保留四字节对齐*****/
parcel_size =ALIGN4_SIZE(d
4000
ata_size);
/****user java parcel readByteArray*******/
/****读取的方法,先读长度,建立数组,在设置偏移量到头,Java Array
读取方式内部会再读取长度来和数据比较*****/
mobj.writeInt32(parcel_size); /**
写数组长度,主要给Java Array
读取方式内部会再读取长度***/
mobj.write(p_parce_buff,parcel_size);
mobj.setDataPosition(0);
/****传输Java接口*****/
dvbclient->notify(msg_id,data1,data2,&mobj);
/****释放Parcelobj*****/
mobj.freeData();
}
}
Java 实现:
private static void postEventFromNative(Object DvbClient_ref,
int what, int arg1, intarg2, Object obj)
{
*************************
if(obj != null){
else if(objinstanceof Parcel){
try{
Parcel parcel_obj = (Parcel)obj;
int parcel_size = parcel_obj.dataSize();
parcel_obj.setDataPosition(0);
intdata_size = parcel_obj.readInt();
byte[]json_buffer = new byte[data_size];
/****读取的方法,先读长度,建立数组,在设置偏移量到头,Java Array
读取方式内部会再读取长度来和数据比较*****/
parcel_obj.setDataPosition(0);
parcel_obj.readByteArray(json_buffer);
/*
/****以下是顺序读写方式,不需要C语言写长度mobj.writeInt32(parcel_size);***/
intvalue = 0;
date_size = parcel_obj.dataSize();
for(inti = 0,j = 0;i < date_size;i += 4,j ++)
{
value= data.readInt();
json_buffer[i] = (byte)(value& 0xff);
json_buffer[i + 1] =(byte)((value>> 8) & 0xff);
json_buffer[i + 2] =(byte)((value >> 16) & 0xff);
json_buffer[i + 3] =(byte)((value >> 24) & 0xff);
}
*/
parcel_obj.recycle();
String json_str = newString(json_buffer);
*************************
}
Java到C的方式:
Java 使用接口不一样,JNI的读取方式也不一样
Parcel parcel_in = Parcel.obtain();
try
{
/* use write bye arraymode
int byte_size =pg_src.Ch_priv_data.length * 4;
byte[] Ch_byte_data =new byte[byte_size];
for(int i = 0; i <pg_src.Ch_priv_data.length;i ++)
{
int j = i * 4;
Ch_byte_data[j +3] = (byte)(pg_src.Ch_priv_data[i] >> 24);
Ch_byte_data[j +2] = (byte)(pg_src.Ch_priv_data[i] >> 16);
Ch_byte_data[j +1] = (byte)(pg_src.Ch_priv_data[i] >> 8);
Ch_byte_data[j] =(byte)(pg_src.Ch_priv_data[i]);
}
parcel_in.writeByteArray(Ch_byte_data);
*/
/*****以上使用的是writeByteArray接口*****/
parcel_in.writeIntArray(pg_src.Ch_priv_data);
/*****此次拥有的是writeIntArray *****/
parcel_in.recycle();
}
catch(Exception e)
{
e.printStackTrace();
}
JNI 对应接口如下:
{
Parcel *p_obj = parcelForJavaObject(env, java_obj);
if (p_obj &&p_obj->dataSize() > 0)
{
data_size =p_obj->dataSize();
/******parce 有效数据总的字节数*****/
p_data_buff = (int*)malloc(data_size + 4);
if(p_data_buff !=NULL)
{
p_obj->setDataPosition(0);
data_size =p_obj->readInt32();
/******parce 在java层写的Array类型个数,如果是writeByteArray 接口,那么就是byte的个数,如果是writeIntArray ,那么就是int 的个数*****/
#if 0 /***use write bye array mode**/
p_obj->read(p_data_buff,data_size);
/**** 直接读取buffer,必须对应javewriteByteArray 接口,且p_data_buff类型为unsigned char *类型*******/
#else
for(int i = 0;i< data_size;i ++)
{
p_data_buff[i]= p_obj->readInt32();
}
/****逐个读取int buffer,必须对应jave writeIntArray接口,且p_data_buff 类型为unsignedint *类型*******/
#endif
free(p_data_buff);
}
}
相关文章推荐
- [Android Studio] *.jar 与 *.aar 的生成与*.aar导入项目方法
- [Android TV]setZOrderMediaOverlay 调整surfaceView Z-Order使用发现
- Android MVP 利用rxjava 避免向Model传入监听方法
- android开发中联系人列表显示字母索引
- Android简易实战教程--第十八话《ListView显示,简单的适配器SimpleAdapter》
- Android简易实战教程--第十八话《ListView显示,简单的适配器SimpleAdapter》
- androidStudio导入工程
- Android 使用Toolbar制作标题栏-design
- android 广播的方法
- [Android Studio] Gradle项目中添加JNI生成文件(.so文件)
- android 倒计时 发送激活码
- 用gradle手动编译出android的简单的apk文件(gradle学习之路二)
- Android Studio上传lib到Jcenter(记录)
- 关于百度地图Android
- 在android布局中使用include和merge标签
- Android—NDK环境搭建及JNI使用详解
- 近百个Android优秀开源项目,覆盖Android开发的每个领域
- Android传递参数总结
- RXAndroid之RxSharedPreference的使用
- 安卓事件分发机制之简明教程