您的位置:首页 > 移动开发 > Android开发

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);

                }

}

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: