To put it simply, parcel is a container for storing and reading data. In the Android system, the binder Process Communication (IPC) uses the parcel class to exchange data between the client and the server, in addition, aidl data is also interactive through parcel. Both Java space and C ++ implement parcel. Because it directly uses memory to read data in C/C ++, it is more efficient.
Analyze the actual ontransact () function of the client and server in the binder mechanism:
- // Parameter description:
- // Code: the ID of the request
- // Data: parameters sent by the client request
- // Reply: The result returned by the server
- // Flags: some additional identifiers, such as flag_oneway, usually 0.
- Virtual status_t ontransact (uint32_t code,
- Const parcel & data,
- Parcel * reply,
- Uint32_t flags = 0 );
CopyCode
We can see the importance of parcel and its usage. Next, I will mainly analyze its storage mechanism.
Common Methods:
Obtain () gets a new parcel, which is equivalent to a new object.
Datasize () to get the actual storage space of the current parcel object
Datacapacity () to get the allocated storage space of the current parcel object,> = datasize () value (Change Time by space)
Datapostion () gets the offset of the current parcel object (similar to the offset of the file stream pointer)
Setdataposition () sets the offset
Recyle () clears and recycles the memory of the parcel object
Writeint (INT) writes an integer
Writefloat (float) writes a floating point number
Writedouble (double) Write a double number
Writestring (string) Write a string
Of course, there are more writexxx () methods, which correspond to readxxx (). For details, see the SDK.
Several noteworthy methods are as follows:
Writeexception () writes an exception in the parcel header.
Writeexception () write "no exception" to the parcel Header
Readexception () is read in the parcel header. If the read value is abnormal, this exception is thrown. Otherwise,ProgramNormal operation.
1. Analysis of parcel
I believe that I have read the previous values and have a preliminary impression on the use of parcel. So what is the internal storage mechanism of parcel? The offset is
What is the situation? Let's recall the value range of the basic data type:
Boolean 1bit 1 byte
Char 16bit 2 bytes
Int 32bit 4 bytes
Long 64bit 8 bytes
Float 32bit 4 bytes
Double 64bit 8 bytes
If you are familiar with the C language, the memory alignment of the structure in the C language is the same as the memory storage mechanism used by parcel, that is, read the minimum byte.
32 bits, that is, 4 bytes. If the value is greater than 4 bytes, it is stored as the actual data type, but must be a multiple of 4 bytes. The basic formula is as follows:
Actual storage Bytes:
Discriminant 1: 32bit (<= 32bit) for example: Boolean, Char, int
Discriminant 2: The actual bytes used (> 32 bit), such as long, float, string, and array.
When we use the readxxx () method, the read method is also as described above:
Actually read Bytes:
Discriminant 1: 32bit (<= 32bit) for example: Boolean, Char, int
Criterion 2: The actual byte size (> 32 bit), for example, long, float, string, and numeric.
As you can see, when we write/read a data, the offset must be at least 4 bytes (32bit). Therefore, the offset formula is as follows:
F (x) = 4x (x = 0, 1 ,... N)
In fact, we can use setdatapostion (INT postion) to directly manipulate the offset when we want to read data. Undoubtedly,
You can set any offset, but the read value may be of a type error. Therefore, be careful when setting the offset read value.
Another note is that the offset caused by writexxx () and readxxx () is shared. For example, after writeint (23,
At this time, datapostion = 4. If we want to read 5, it is not possible to simply use readint (), and we can only get 0. In this case, we can only
Setdataposition (0) is set to the starting offset, and four bytes are read from the starting position, that is, 23. Therefore, when reading a value, you may need to use
Setdatapostion (INT postion) changes the offset to our value.
The setdataposition () method is used to quickly read data of only a certain type in our parcel object.
All values. The specific method is as follows:
-
- View plainprint?
-
- /**
-
- * Prerequisites: parcel has multiple objects of the same type. In this example, we describe 10 float objects:
-
- */
-
- Public void readsametype (){
- Parcel parcel = parcel. Obtain ();
-
- For (INT I = 0; I <10; I ++ ){
-
- Parcel. writedouble (I );
-
- Log. I (TAG, "Write double ---->" + getparcelinfo ());
-
- }
-
- // Method 1: display the Set offset
-
- Int I = 0;
-
- Int datasize = parcel. datasize ();
-
- While (I <datasize ){
- Parcel. setdataposition (I );
-
- Double fvalue = parcel. readdouble ();
-
- Log. I (TAG, "Read double is =" + fvalue + ", --->" + getparcelinfo ());
-
- I + = 8; // double occupies 8 bytes
-
- }
-
- // Method 2. Because the object type is consistent, we can directly use readxxx () to read the value and produce an offset.
-
- // Parcel. setdataposition (0 );//
-
- // While (parcel. dataposition () <parcel. datasize ()){
- // Double fvalue = parcel. readdouble ();
-
- // Log. I (TAG, "Read double is =" + fvalue + ", --->" + getparcelinfo ());
-
- //}
-
- }
Copy code
Due to the possible deviation of the read value, a default value can be:
1. When reading a complex object: when the object matches, the object at the current offset is returned;
If the object does not match, null is returned;
2. When reading a simple object: when the object matches, the object at the current offset is returned;
If the object does not match, 0 is returned;
Next, we will provide a simple storage space map for parcel. We hope you can better understand it while understanding it. It's a little simple. Please forgive me.
I believe that through the previous introduction, you will be very familiar with the storage mechanism of parcel. The following is an application for practice.
1. The layout file is as follows:
-
- <Span> <? XML version = "1.0" encoding = "UTF-8"?>
-
- <Linearlayout xmlns: Android = "http://schemas.android.com/apk/res/android"
-
- Android: Orientation = "vertical" Android: layout_width = "fill_parent"
-
- Android: layout_height = "fill_parent">
- <Textview Android: layout_width = "fill_parent"
-
- Android: layout_height = "wrap_content" Android: text = "@ string/Hello"/>
-
- <Linearlayout Android: Orientation = "horizontal"
-
- Android: layout_width = "fill_parent" Android: layout_height = "wrap_content">
-
- <Button Android: Id = "@ + ID/btwritebyte" Android: layout_width = "wrap_content"
-
- Android: layout_height = "wrap_content" Android: text = "Write a byte value"> </button>
-
- <Button Android: Id = "@ + ID/btwriteint" Android: layout_width = "wrap_content"
- Android: layout_height = "wrap_content" Android: text = "write an int value"> </button>
-
- </Linearlayout>
-
- <Linearlayout Android: Orientation = "horizontal"
-
- Android: layout_width = "fill_parent" Android: layout_height = "wrap_content">
-
- <Button Android: Id = "@ + ID/btwritedouble" Android: layout_width = "wrap_content"
-
- Android: layout_height = "wrap_content" Android: text = "Write a double value"> </button>
-
- <Button Android: Id = "@ + ID/btwritestring" Android: layout_width = "wrap_content"
- Android: layout_height = "wrap_content" Android: text = "Write a string value"> </button>
-
- </Linearlayout>
-
- <View Android: layout_width = "fill_parent" Android: layout_height = "2dip"
-
- Android: Background = "# ff1493"> </View>
-
- <Linearlayout Android: Orientation = "horizontal"
-
- Android: layout_margintop = "5dip" Android: layout_width = "fill_parent"
-
- Android: layout_height = "wrap_content">
-
- <Button Android: Id = "@ + ID/btreadbyte" Android: layout_width = "wrap_content"
- Android: layout_height = "wrap_content" Android: text = "read a byte value"> </button>
-
- <Button Android: Id = "@ + ID/btreadint" Android: layout_width = "wrap_content"
-
- Android: layout_height = "wrap_content" Android: text = "read an int value"> </button>
-
- </Linearlayout>
-
- <Linearlayout Android: Orientation = "horizontal"
-
- Android: layout_width = "fill_parent" Android: layout_height = "wrap_content">
-
- <Button Android: Id = "@ + ID/btreaddouble" Android: layout_width = "wrap_content"
- Android: layout_height = "wrap_content" Android: text = "read a double value"> </button>
-
- <Button Android: Id = "@ + ID/btreadstring" Android: layout_width = "wrap_content"
-
- Android: layout_height = "wrap_content" Android: text = "read a string value"> </button>
-
- </Linearlayout>
-
- <View Android: layout_width = "fill_parent" Android: layout_height = "2dip"
-
- Android: Background = "# ff1493"> </View>
-
- <Button Android: Id = "@ + ID/btsametype" Android: layout_width = "wrap_content"
- Android: layout_height = "wrap_content" Android: text = "use setdataposition to read multiple values"> </button>
-
- </Linearlayout>
Copy code
2. The configuration file is as follows:
-
- <? XML version = "1.0" encoding = "UTF-8"?>
-
- <Manifest xmlns: Android = "http://schemas.android.com/apk/res/android"
-
- Package = "com. qinjuning. parcel"
-
- Android: versioncode = "1"
-
- Android: versionname = "1.0" type = "codeph" text = "/codeph">
-
- <Application Android: icon = "@ drawable/icon" Android: Label = "@ string/app_name">
- <Activity Android: Name = ". mainactivity" Android: Label = "@ string/app_name">
-
- <Intent-filter>
-
- <Action Android: Name = "android. Intent. Action. Main"/>
-
- <Category Android: Name = "android. Intent. Category. launcher"/>
-
- </Intent-filter>
-
- </Activity>
-
- </Application>
-
- </Manifest>
Copy code
3. The main program file is as follows:
- <Span> public class mainactivity extends activity implements onclicklistener {
-
-
- Private Static string tag = "parceltest ";
-
- // Button ID
-
- Private Static int [] btids = new int [] {R. Id. btwritebyte, R. Id. btwriteint,
-
- R. Id. btreaddouble, R. Id. btwritestring, R. Id. btreadbyte,
-
- R. Id. btreadint, R. Id. btreaddouble, R. Id. btreadstring,
-
- R. Id. btsametype };
-
- // The current value of each type
-
- Private byte cur_byte = 1; // false for each write
- Private int cur_int = 10; // write value cur_int ++;
-
- Private double cur_float = 100w.d; // write value cur_float ++;
-
- Private string cur_str = "qinjun -->" + cur_int; // write value "qinjun -->" + cur_int
-
-
- Private parcel = NULL;
-
-
- @ Override
-
- Public void oncreate (bundle savedinstancestate ){
-
- Super. oncreate (savedinstancestate );
-
- Setcontentview (R. layout. Main );
-
- For (INT I = 0; I <btids. length; I ++ ){
- Button bt = (button) findviewbyid (btids [I]);
-
- Bt. setonclicklistener (this );
-
- }
-
- Parcel = parcel. Obtain (); // obtain a parcel object, which is equivalent to a new object and the initial size is 0.
-
- Log. I (TAG, "the original parcel Info" + getparcelinfo ());
-
- }
-
-
- @ Override
-
- Public void onclick (view ){
-
- // Todo auto-generated method stub
- Int viewviewid = view. GETID ();
-
- Switch (viewid ){
-
- Case R. Id. btwritebyte:
-
- Parcel. setdataposition (0 );
-
- Parcel. writebyte (cur_byte );
-
- Log. I (TAG, "After Write byte, --->" + getparcelinfo ());
-
- Break;
-
- Case R. Id. btwriteint:
-
- Parcel. writeint (cur_int );
- Log. I (TAG, "After Write int, --->" + getparcelinfo ());
-
- Break;
-
- Case R. Id. btwritedouble:
-
- Parcel. writedouble (cur_float );
-
- Log. I (TAG, "After Write float, --->" + getparcelinfo ());
-
- Break;
-
- Case R. Id. btwritestring:
-
- Parcel. writestring (cur_str );
- Log. I (TAG, "After Write string, --->" + getparcelinfo ());
-
- Break;
-
- Case R. Id. btreadbyte:
-
- Byte B = parcel. readbyte ();
-
- Log. I (TAG, "Read byte is =" + B + ", --->" + getparcelinfo ()
-
- + "String ");
-
- Break;
-
- Case R. Id. btreadint:
- Int I = parcel. readint ();
-
- Log. I (TAG, "Read Int Is =" + I + ", --->" + getparcelinfo ());
-
- Break;
-
- Case R. Id. btreaddouble:
-
- Float F = parcel. readfloat ();
-
- Readsametype ();
-
- Log. I (TAG, "Read float is =" + F + ", --->" + getparcelinfo ());
-
- Break;
- Case R. Id. btreadstring:
-
- Parcel. setdataposition (0 );
-
- String STR = parcel. readstring ();
-
- Log. I (TAG, "Read float is =" + STR + ", --->" + getparcelinfo ());
-
- Break;
-
- Case R. Id. btsametype:
-
- Readsametype ();
-
- Break;
-
- Default:
- Break;
-
- }
-
- }
-
-
- Private string getparcelinfo () {// get the parcel information
-
- Return "datasize =" + parcel. datasize () + ", datacapacity ="
-
- + Parcel. datacapacity () + ", datapositon ="
-
- + Parcel. dataposition ();
-
- }
-
-
- /**
-
- * Prerequisites: parcel has multiple objects of the same type. In this example, we describe 10 float objects:
- */
-
- Public void readsametype (){
-
-
- For (INT I = 0; I <10; I ++ ){
-
- Parcel. writedouble (I );
-
- Log. I (TAG, "Write double ---->" + getparcelinfo ());
-
- }
-
- // Method 1: display the Set offset
-
- Int I = 0;
-
- Int datasize = parcel. datasize ();
- While (I <datasize ){
-
- Parcel. setdataposition (I );
-
- Double fvalue = parcel. readdouble ();
-
- Log. I (TAG, "Read double is =" + fvalue + ", --->" + getparcelinfo ());
-
- I + = 8; // double occupies 8 bytes
-
- }
-
- // Method 2. Because the object type is consistent, we can directly use readxxx () to read the value and produce an offset.
-
- // Parcel. setdataposition (0 );//
- // While (parcel. dataposition () <parcel. datasize ()){
-
- // Double fvalue = parcel. readdouble ();
-
- // Log. I (TAG, "Read double is =" + fvalue + ", --->" + getparcelinfo ());
-
- //}
-
- }
-
- }
Copy code
Because there may be type conversion during the value, the expected results may not be generated when you click the button. Therefore, the correctness of the offset value must be ensured.
Reprinted from: http://www.eoeandroid.com/blog-129327-2029.html