`
ruirui516888
  • 浏览: 137185 次
文章分类
社区版块
存档分类
最新评论

探索Android中的Parcel

 
阅读更多

一、Android中的Parcel是什么

Parcel,翻译过来是“打包”的意思。打包干什么呢?是为了序列化。

如果要在进程之间传递一个整数,很简单,直接传就是行了;如果要传一个字符串,就稍微复杂了点:需先分配一块可以容纳字符串的内存,然后将字符串复制到内存中,再传递(新手可能问:为啥不直接把字符串的引用传过去呢?学过C/C++的地球人都知道:进程有自己的内存地址空间,一个进程中的1000地址可能在另一个进程中是100000,java对象的引用跟本上还是内存地址);再如果要传递一个类的实例呢?也是先为类分配内存,然后复制一份再传递可以吗?我认为不可以,我至少可以找到一个理由:类中成员除了属性还有方法,即使属性能完整传过去,但还有方法呢?方法是独立于类对象存在的,所以到另一个进程中再引用同一个方法就要出错了,还是因为独立地址空间的原因。

Android开发中,很经常在各activity之间传递数据,而跟据Android的设计架构,即使同一个程序中的Activity都不一定运行在同一个进程中,所以处理数据传递时你不能老假设两个activity都运行于同一进程,那么只能按进程间传递数据来处理,使之具有最广泛的适应性。

  那么到底如何在进程之间传递类对象呢?简单来说可以这样做:在进程A中把类中的非默认值的属性和类的唯一标志打成包(这就叫序列化),把这个包传递到进程B,进程B接收到包后,跟据类的唯一标志把类创建出来,然后把传来的属性更新到类对象中,这样进程A和进程B中就包含了两个完全一样的类对象。

二、探索Android中的Parcel机制(上)

转自:http://blog.csdn.net/caowenbin/article/details/6532217(作者:曹文斌)

一.先从Serialize说起

我们都知道JAVA中的Serialize机制,译成串行化、序列化……,其作用是能将数据对象存入字节流当中,在需要时重新生成对象。主要应用是利用外部存储设备保存对象状态,以及通过网络传输对象等。

二.Android中的新的序列化机制

在Android系统中,定位为针对内存受限的设备,因此对性能要求更高,另外系统中采用了新的IPC(进程间通信)机制,必然要求使用性能更出色的对象传输方式。在这样的环境下,Parcel被设计出来,其定位就是轻量级的高效的对象序列化和反序列化机制。

三.Parcel类的背后

在Framework中有parcel类,源码路径是:

Frameworks/base/core/java/android/os/Parcel.java

典型的源码片断如下:

  1. /**
  2. *WriteanintegervalueintotheparcelatthecurrentdataPosition(),
  3. *growingdataCapacity()ifneeded.
  4. */
  5. publicfinalnativevoidwriteInt(intval);
  6. /**
  7. *WritealongintegervalueintotheparcelatthecurrentdataPosition(),
  8. *growingdataCapacity()ifneeded.
  9. */
  10. publicfinalnativevoidwriteLong(longval);

从中我们看到,从这个源程序文件中我们看不到真正的功能是如何实现的,必须透过JNI往下走了。于是,Frameworks/base/core/jni/android_util_Binder.cpp中找到了线索

  1. staticvoidandroid_os_Parcel_writeInt(JNIEnv*env,jobjectclazz,jintval)
  2. {
  3. Parcel*parcel=parcelForJavaObject(env,clazz);
  4. if(parcel!=NULL){
  5. conststatus_terr=parcel->writeInt32(val);
  6. if(err!=NO_ERROR){
  7. jniThrowException(env,"java/lang/OutOfMemoryError",NULL);
  8. }
  9. }
  10. }
  11. staticvoidandroid_os_Parcel_writeLong(JNIEnv*env,jobjectclazz,jlongval)
  12. {
  13. Parcel*parcel=parcelForJavaObject(env,clazz);
  14. if(parcel!=NULL){
  15. conststatus_terr=parcel->writeInt64(val);
  16. if(err!=NO_ERROR){
  17. jniThrowException(env,"java/lang/OutOfMemoryError",NULL);
  18. }
  19. }
  20. }

从这里我们可以得到的信息是函数的实现依赖于Parcel指针,因此还需要找到Parcel的类定义,注意,这里的类已经是用C++语言实现的了。

找到Frameworks/base/include/binder/parcel.h和Frameworks/base/libs/binder/parcel.cpp。终于找到了最终的实现代码了。

有兴趣的朋友可以自己读一下,不难理解,这里把基本的思路总结一下:

1.整个读写全是在内存中进行,主要是通过malloc()、realloc()、memcpy()等内存操作进行,所以效率比JAVA序列化中使用外部存储器会高很多;

2.读写时是4字节对齐的,可以看到#define PAD_SIZE(s) (((s)+3)&~3)这句宏定义就是在做这件事情;

3.如果预分配的空间不够时newSize = ((mDataSize+len)*3)/2;会一次多分配50%;

4.对于普通数据,使用的是mData内存地址,对于IBinder类型的数据以及FileDescriptor使用的是mObjects内存地址。后者是通过flatten_binder()和unflatten_binder()实现的,目的是反序列化时读出的对象就是原对象而不用重新new一个新对象。

三、探索Android中的Parcel机制(下)

上一篇中我们透过源码看到了Parcel背后的机制,本质上把它当成一个Serialize就可以了,只是它是在内存中完成的序列化和反序列化,利用的是连续的内存空间,因此会更加高效。

我们接下来要说的是Parcel类如何应用。就应用程序而言,最常见使用Parcel类的场景就是在Activity间传递数据。没错,在Activity间使用Intent传递数据的时候,可以通过Parcelable机制传递复杂的对象。

在下面的程序中,MyColor用于保存一个颜色值,MainActivity在用户点击屏幕时将MyColor对象设成红色,传递到SubActivity中,此时SubActivity的TextView显示为红色的背景;当点击SubActivity时,将颜色值改为绿色,返回MainActivity,期望的是MainActivity的TextView显示绿色背景。

来看一下MyColor类的实现代码:

  1. packagecom.wenbin.test;
  2. importandroid.graphics.Color;
  3. importandroid.os.Parcel;
  4. importandroid.os.Parcelable;
  5. /**
  6. *@author曹文斌
  7. *http://blog.csdn.net/caowenbin
  8. *
  9. */
  10. publicclassMyColorimplementsParcelable{
  11. privateintcolor=Color.BLACK;
  12. MyColor(){
  13. color=Color.BLACK;
  14. }
  15. MyColor(Parcelin){
  16. color=in.readInt();
  17. }
  18. publicintgetColor(){
  19. returncolor;
  20. }
  21. publicvoidsetColor(intcolor){
  22. this.color=color;
  23. }
  24. @Override
  25. publicintdescribeContents(){
  26. return0;
  27. }
  28. @Override
  29. publicvoidwriteToParcel(Parceldest,intflags){
  30. dest.writeInt(color);
  31. }
  32. publicstaticfinalParcelable.Creator<MyColor>CREATOR
  33. =newParcelable.Creator<MyColor>(){
  34. publicMyColorcreateFromParcel(Parcelin){
  35. returnnewMyColor(in);
  36. }
  37. publicMyColor[]newArray(intsize){
  38. returnnewMyColor[size];
  39. }
  40. };
  41. }


该类实现了Parcelable接口,提供了默认的构造函数,同时也提供了可从Parcel对象开始的构造函数,另外还实现了一个static的构造器用于构造对象和数组。代码很简单,不一一解释了。

再看MainActivity的代码:

  1. packagecom.wenbin.test;
  2. importandroid.app.Activity;
  3. importandroid.content.Intent;
  4. importandroid.graphics.Color;
  5. importandroid.os.Bundle;
  6. importandroid.view.MotionEvent;
  7. /**
  8. *@author曹文斌
  9. *http://blog.csdn.net/caowenbin
  10. *
  11. */
  12. publicclassMainActivityextendsActivity{
  13. privatefinalintSUB_ACTIVITY=0;
  14. privateMyColorcolor=newMyColor();
  15. @Override
  16. publicvoidonCreate(BundlesavedInstanceState){
  17. super.onCreate(savedInstanceState);
  18. setContentView(R.layout.main);
  19. }
  20. @Override
  21. protectedvoidonActivityResult(intrequestCode,intresultCode,Intentdata){
  22. super.onActivityResult(requestCode,resultCode,data);
  23. if(requestCode==SUB_ACTIVITY){
  24. if(resultCode==RESULT_OK){
  25. if(data.hasExtra("MyColor")){
  26. color=data.getParcelableExtra("MyColor");//Notice
  27. findViewById(R.id.text).setBackgroundColor(color.getColor());
  28. }
  29. }
  30. }
  31. }
  32. @Override
  33. publicbooleanonTouchEvent(MotionEventevent){
  34. if(event.getAction()==MotionEvent.ACTION_UP){
  35. Intentintent=newIntent();
  36. intent.setClass(this,SubActivity.class);
  37. color.setColor(Color.RED);
  38. intent.putExtra("MyColor",color);
  39. startActivityForResult(intent,SUB_ACTIVITY);
  40. }
  41. returnsuper.onTouchEvent(event);
  42. }
  43. }

下面是SubActivity的代码:

  1. packagecom.wenbin.test;
  2. importandroid.app.Activity;
  3. importandroid.content.Intent;
  4. importandroid.graphics.Color;
  5. importandroid.os.Bundle;
  6. importandroid.view.MotionEvent;
  7. importandroid.widget.TextView;
  8. /**
  9. *@author曹文斌
  10. *http://blog.csdn.net/caowenbin
  11. *
  12. */
  13. publicclassSubActivityextendsActivity{
  14. privateMyColorcolor;
  15. @Override
  16. publicvoidonCreate(BundlesavedInstanceState){
  17. super.onCreate(savedInstanceState);
  18. setContentView(R.layout.main);
  19. ((TextView)findViewById(R.id.text)).setText("SubActivity");
  20. Intentintent=getIntent();
  21. if(intent!=null){
  22. if(intent.hasExtra("MyColor")){
  23. color=intent.getParcelableExtra("MyColor");
  24. findViewById(R.id.text).setBackgroundColor(color.getColor());
  25. }
  26. }
  27. }
  28. @Override
  29. publicbooleanonTouchEvent(MotionEventevent){
  30. if(event.getAction()==MotionEvent.ACTION_UP){
  31. Intentintent=newIntent();
  32. if(color!=null){
  33. color.setColor(Color.GREEN);
  34. intent.putExtra("MyColor",color);
  35. }
  36. setResult(RESULT_OK,intent);
  37. finish();
  38. }
  39. returnsuper.onTouchEvent(event);
  40. }
  41. }

下面是main.xml的代码:

  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="vertical"
  4. android:layout_width="fill_parent"
  5. android:layout_height="fill_parent"
  6. >
  7. <TextView
  8. android:layout_width="fill_parent"
  9. android:layout_height="wrap_content"
  10. android:text="@string/hello"
  11. android:id="@+id/text"
  12. />
  13. </LinearLayout>

注意的是在MainActivity的onActivityResult()中,有一句color=data.getParcelableExtra("MyColor"),这说明的是反序列化后是一个新的MyColor对象,因此要想使用这个对象,我们做了这个赋值语句。

记得在上一篇《探索Android中的Parcel机制(上)》中提到,如果数据本身是IBinder类型,那么反序列化的结果就是原对象,而不是新建的对象,很显然,如果是这样的话,在反序列化后在MainActivity中就不再需要color=data.getParcelableExtra("MyColor")这句了。因此,换一种MyColor的实现方法,令其中的int color成员变量使用IBinder类型的成员变量来表示。

新建一个BinderData类继承自Binder,代码如下:

  1. packagecom.wenbin.test;
  2. importandroid.os.Binder;
  3. /**
  4. *@author曹文斌
  5. *http://blog.csdn.net/caowenbin
  6. *
  7. */
  8. publicclassBinderDataextendsBinder{
  9. publicintcolor;
  10. }

修改MyColor的代码如下:

  1. packagecom.wenbin.test;
  2. importandroid.graphics.Color;
  3. importandroid.os.Parcel;
  4. importandroid.os.Parcelable;
  5. /**
  6. *@author曹文斌
  7. *http://blog.csdn.net/caowenbin
  8. *
  9. */
  10. publicclassMyColorimplementsParcelable{
  11. privateBinderDatadata=newBinderData();
  12. MyColor(){
  13. data.color=Color.BLACK;
  14. }
  15. MyColor(Parcelin){
  16. data=(BinderData)in.readValue(BinderData.class.getClassLoader());
  17. }
  18. publicintgetColor(){
  19. returndata.color;
  20. }
  21. publicvoidsetColor(intcolor){
  22. data.color=color;
  23. }
  24. @Override
  25. publicintdescribeContents(){
  26. return0;
  27. }
  28. @Override
  29. publicvoidwriteToParcel(Parceldest,intflags){
  30. dest.writeValue(data);
  31. }
  32. publicstaticfinalParcelable.Creator<MyColor>CREATOR
  33. =newParcelable.Creator<MyColor>(){
  34. publicMyColorcreateFromParcel(Parcelin){
  35. returnnewMyColor(in);
  36. }
  37. publicMyColor[]newArray(intsize){
  38. returnnewMyColor[size];
  39. }
  40. };
  41. }

去掉MainActivity的onActivityResult()中的color=data.getParcelableExtra("MyColor")一句,变成:

  1. @Override
  2. protectedvoidonActivityResult(intrequestCode,intresultCode,Intentdata){
  3. super.onActivityResult(requestCode,resultCode,data);
  4. if(requestCode==SUB_ACTIVITY){
  5. if(resultCode==RESULT_OK){
  6. if(data.hasExtra("MyColor")){
  7. findViewById(R.id.text).setBackgroundColor(color.getColor());
  8. }
  9. }
  10. }
  11. }

再次运行程序,结果符合预期。

以上就是Parcel在应用程序中的使用方法,与Serialize还是挺相似的,详细的资料当然还是要参考Android SDK的开发文档了。



三、Android Parcel理解

android 中Parcel 的使用,他是一个存储基本数据类型和引用数据类型的容器,在andorid 中通过IBinder来绑定数据在进程间传递数据。
Parcel parcel = Parcel.obtain();// 获取一个Parcel 对象
下面就可以对其进行方法进行操作了,createXXX(),wirteXXX(),readXXX(),
其中dataPosition(),返回当前Parcel 当前对象存储数据的偏移量,而setDataPosition(),设置当前Parcel 对象的偏移量,方便读取parcel 中的数据,可问题就出在我读取出来的数据要么是空(null),要么永远是第一个偏移量处的值,存储和读取数据的。Parcel采用什么机制实现的,是以什么形式的存储的,然后我才能任意对其操作,读取目标数据。
基本数据类型的取值范围,
boolean 1bit
short 16bit
int 32bit
long 64bit
float 32bit
double 64bit
char 16bit
byte 8bit
由此我可以猜想,Parcel 32bit 作为基本单位存储写入的变量,4byte*8=32bit,在内存中的引用地址变量是采用16进制进行编码,且作为偏移量,即偏移量是4的倍数,0,4,8,12,16,20,24,28,32,36,40,44,48......4*N,
f(x) = 4*y{y>=0&y是自然数}
我想绝对不会出现向偏移量是3,6,9这样的数据。。。
由此我们可以推断出,无论他存储的是基本数据类型或引用数据类型的变量,都是以32bit基本单位作为偏移量,
parcel.writeInt(1);
parcel.writeInt(2);
parcel.writeInt(3);
parcel.writeInt(4);
parcel.writeInt(5);
parcel.writeInt(6);
parcel.writeInt(7);
parcel.writeInt(81011111);
parcel.writeFloat(1f);
parcel.writeFloat(1000000000000000000000000000000000000f);

parcel.writeXXX(),每写一次数据,在32bit的空间里能够存储要放入的变量,怎只占一个偏移量,也就之一动4个位置,而当存储的数据如 parcel.writeFloat(1000000000000000000000000000000000000f);他就自动往后移动,
parcel.writeString("a");
parcel.writeString("b");
parcel.writeString("d");
parcel.writeString("c");

parcel.writeString("abcd"); 的区别。有此可见,他的内存的分配原来是这样的。
那我怎样才能把我存进去的书据依次的去出来呢?setDataPosition(),设置parcel 的偏移量,在readXXX(),读取数据
int size = parcel.dataSize();
int i = 0;
while (i <= size ) {
parcel.setDataPosition(i);
int curr_int = parcel.readInt();
i+=4;
int j = 0;
j++;
}
由此可见parcel 写入数据是按照32bit 为基本的容器,依次存储写入的数据,基本和引用(其实引用的也是有多个基本数据类型组合而成OBJECTS-属性|方法),读取的时候我们就可以按照这种规律根据目标数据的偏移量的位置(curr_position),以及偏移量的大小(size),,取出已经存进去的数据了
int i = curr_position;
while (i <= size ) {
parcel.setDataPosition(i);
int curr_int = parcel.readXXXt();
i+=4;
int j = 0;
j++;
}
这样就ok 了
他的createXXX()方法现在没用,用了在说吧!
总结一句话,java 中 基本数据类型的取值范围,引用类型的数据,相当于c中的指针,以及各进制之间的相互转换和灵活的引用,以及定制自己想要的任意进制数据类型。


四、Android开发:什么是Parcel(2)

转自:http://blog.csdn.net/nkmnkm/article/details/6453391

上回书解释了IBinder,这回详细解释一下Parcel,以下是对android sdk 文档的翻议:
Parcel是一个容器,它主要用于存储序列化数据,然后可以通过Binder在进程间传递这些数据(要了解为什么要序列化,请参考:http://blog.csdn.net/nkmnkm/archive/2011/05/28/6451699.aspx
。Parcel可以包含原始数据类型(用各种对应的方法写入,比如writeInt(),writeFloat()等),可以包含Parcelable对象,它还包含了一个活动的IBinder对象的引用,这个引用导致另一端接收到一个指向这个IBinder的代理IBinder。

注:Parcel不是一般目的的序列化机制。这个类被设计用于高性能的IPC传输。因此不适合把Parcel写入永久化存储中,因为Parcel中的数据类型的实现的改变会导致旧版的数据不可读。

Parcel的一坨一坨的API用于解决不同类型数据的读写。这些函数们主要有六种类型。

1原始类

这类方法们主要读写原始数据类型。它们是:writeByte(byte), readByte(), writeDouble(double), readDouble(), writeFloat(float), readFloat(), writeInt(int), readInt(), writeLong(long), readLong(), writeString(String), readString().大多数其它数据的操作都是基于这些方法。

2原始数组类

这类方法用于读写原始数据组成的数组。在向数组写数据时先写入数组的长度再写入数据。读数组的方法可以将数据读到已存在的数组中,也可以创建并返回一个新数组。它们是:

  • writeBooleanArray(boolean[]), readBooleanArray(boolean[]), createBooleanArray()
    writeByteArray(byte[]), writeByteArray(byte[], int, int), readByteArray(byte[]), createByteArray()
    writeCharArray(char[]), readCharArray(char[]), createCharArray()
    writeDoubleArray(double[]), readDoubleArray(double[]), createDoubleArray()
    writeFloatArray(float[]), readFloatArray(float[]), createFloatArray()
    writeIntArray(int[]), readIntArray(int[]), createIntArray()
    writeLongArray(long[]), readLongArray(long[]), createLongArray()
    writeStringArray(String[]), readStringArray(String[]), createStringArray().
    writeSparseBooleanArray(SparseBooleanArray), readSparseBooleanArray().

3 Parcelable类
Parcelable为对象从Parcel中读写自己提供了极其高效的协议。你可以使用直接的方法 writeParcelable(Parcelable, int) 和 readParcelable(ClassLoader) 或 writeParcelableArray(T[], int) and readParcelableArray(ClassLoader) 进行读写。这些方法们把类的信息和数据都写入Parcel,以使将来能使用合适的类装载器重新构造类的实例。

还有一些方法提供了更高效的操作Parcelable们的途径,它们是:writeTypedArray(T[], int), writeTypedList(List), readTypedArray(T[], Parcelable.Creator) and readTypedList(List, Parcelable.Creator)。这些方法不会写入类的信息,取而代之的是:读取时必须能知道数据属于哪个类并传入正确的Parcelable.Creator来创建对象而不是直接构造新对象。(更加高效的读写单个Parcelable对象的方法是:直接调用Parcelable.writeToParcel()和Parcelable.Creator.createFromParcel())

4 Bundles类

Bundles是一种类型安全的Map型容器,可用于存储任何不同类型的数据。它具有很多对讀写数据的性能优化,并且它的类型安全机制避免了当把它的数据封送到Parcel中时由于类型错误引起的BUG的调试的麻烦,可以使用的方法为: writeBundle(Bundle), readBundle(), and readBundle(ClassLoader)。

5 活动对象类

Parcel的一个非同寻常的特性是读写活对象的能力。对于活动对象,它们的内容实际上并没有写入,而是仅写入了一个令牌来引用这个对象。当从Parcel中读取这个对象时,你不会获取一个新的对象实例,而是直接得到那个写入的对象。有两种活动对象可操作:

Binder对象。它是Android跨进程通讯的基础。这种对象可被写入Parcel,并在读取时你将得到原始的对象或一个代理对象(可以想象:在进程内时得到原始的对象,在进程间时得到代理对象)。可以使用的方法们是: writeStrongBinder(IBinder), writeStrongInterface(IInterface), readStrongBinder(), writeBinderArray(IBinder[]), readBinderArray(IBinder[]), createBinderArray(), writeBinderList(List), readBinderList(List), createBinderArrayList()。

FileDescriptor对象。它代表了原始的Linux文件描述符,它可以被写入Parcel并在读取时返回一个ParcelFileDescriptor对象用于操作原始的文件描述符。ParcelFileDescriptor是原始描述符的一个复制:对象和fd不同,但是都操作于同一文件流,使用同一个文件位置指针,等等。可以使用的方法是:writeFileDescriptor(FileDescriptor), readFileDescriptor()。

6无类型容器类

一类final方法,用于读写标准的java容器类。这些方法们是:writeArray(Object[]), readArray(ClassLoader), writeList(List), readList(List, ClassLoader), readArrayList(ClassLoader), writeMap(Map), readMap(Map, ClassLoader), writeSparseArray(SparseArray), readSparseArray(ClassLoader)。


android 复杂数据模型的传递
转:
http://hi.baidu.com/penguu8/blog/item/884638a2c42fa0afca130c5b.html

很久没有写了,一直不知道写什么,最近在研究怎样在Android的开发中传递一些复杂的数据。其实网上已经有很多的人都写过相关的,但是看了后,发现都大同小异,缺少我想要看到的地方。所以我打算做一下这方面的探讨。

有时候在团队开发的时候,我们会考虑创建一些复杂(包含的数据类型有多种)的Model,方便在数据上的传输和处理。一些关于android中对于这类model的传递,一般都是实现Parcelable或者是Serializable这两个接口,这两个接口有一些不同,Serializable接口一般只做一些简单的数据类型传递,而Parcelable可以实现很多复杂的情况,比如Parcelable中嵌套了图片,实现了Parcelable的其他模型等,而对于这种复杂的类型,网上很难找到这样的内容,所以我做了一个例子来解决。

首先,我创建了三个数据model:ArtistMode,TrackModel和AlbumModel,根据名字大家应该能够明白。这三个类中只有ArtistModel是实现的Serializable接口,另外两个都是实现的Parcelable接口。

ArtistModel:歌手信息,包含了歌手的名字,年龄,性别和国籍,这些都是简单的String和int型数据;

TrackMode:歌曲信息,包含歌曲的名字,发行时间和歌手列表(这里采用了一个存放ArtistMode的List);

AlbumModel:专辑信息,包含了专辑的名字,歌手信息(ArtistMode),发行时间和歌曲列表(一个存放TrackModel的List)。

介绍完了三个模型后,我们就要具体实现模型中数据的读写了。对于Parcelable或者是Serializable该复写哪些方法我也就不多说,网上对于这个介绍的都很多。现在是说说一个需要注意的地方。

Java代码
  1. @Override
  2. publicvoidwriteToParcel(Parceldest,intflag){
  3. dest.writeString(albumName);
  4. dest.writeSerializable(artistModel);
  5. dest.writeList(trackList);
  6. dest.writeString(releaseTime);
  7. }
  8. publicstaticfinalParcelable.Creator<AlbumModel>CREATOR=newParcelable.Creator<AlbumModel>(){
  9. @Override
  10. publicAlbumModelcreateFromParcel(Parcelsource){
  11. AlbumModelmodel=newAlbumModel();
  12. model.albumName=source.readString();
  13. model.artistModel=(ArtistModel)source.readSerializable();
  14. //必须实例化
  15. model.trackList=newArrayList<TrackModel>();
  16. source.readList(model.trackList,getClass().getClassLoader());
  17. model.releaseTime=source.readString();
  18. returnmodel;
  19. }
  20. @Override
  21. publicAlbumModel[]newArray(intsize){
  22. returnnewAlbumModel[size];
  23. }
  24. };
@Override	public void writeToParcel(Parcel dest, int flag) {		dest.writeString(albumName);		dest.writeSerializable(artistModel);		dest.writeList(trackList);		dest.writeString(releaseTime);	}	public static final Parcelable.Creator<AlbumModel> CREATOR = new Parcelable.Creator<AlbumModel>() {		@Override		public AlbumModel createFromParcel(Parcel source) {			AlbumModel model = new AlbumModel();			model.albumName = source.readString();			model.artistModel = (ArtistModel) source.readSerializable();			// 必须实例化			model.trackList = new ArrayList<TrackModel>();			source.readList(model.trackList, getClass().getClassLoader());			model.releaseTime = source.readString();			return model;		}		@Override		public AlbumModel[] newArray(int size) {			return new AlbumModel[size];		}	};

注意上面在writeToParcel()方法中我用了一个dest.writeList(trackList);来传递一个List。相对应的读取里面,有这段代码:

Java代码
  1. //必须实例化
  2. model.trackList=newArrayList<TrackModel>();
  3. source.readList(model.trackList,getClass().getClassLoader());
// 必须实例化			model.trackList = new ArrayList<TrackModel>();			source.readList(model.trackList, getClass().getClassLoader());

这里要想读出存放进去的List,就必须先将List实例化,否则就读不出来数据。这是我在查看Android的源码后发型的,对于数据的读写,系统提供了一个比较全的读取方法是readValue,这个方法中,系统会自动进行数据匹配的,但是具体的使用,大家可以去尝试,只要明白读写的方式后,就不难实现了。

上面是一个唯一需要特别注意的地方。其余的数据类型该怎么传递,大家可以尝试,接下来我会把整个项目上传,大家有什么问题可以留言。

Intent之间传递object的两种方法

Intent之间传递object的两种方法:被传递的对象的类实现Parcelable接口,或者实现Serialiable接口。

http://www.anddev.org/putting_an_object_into_a_bundle-t6431.html

http://blog.csdn.net/Android_Tutor/archive/2010/07/16/5740845.aspx

Method 1

  1. package de.padde.test;
  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.os.Parcelable;
  5. import android.os.Parcel;
  6. public class Test extends Activity {
  7. public void onCreate(Bundle savedInstanceState) {
  8. super.onCreate(savedInstanceState);
  9. setContentView(R.layout.main);
  10. if(!savedInstanceState.isEmpty()) {
  11. SaveMe state = savedInstanceState.getParcelable("laststate");
  12. }
  13. }
  14. protected void onPause() {
  15. Bundle b = new Bundle();
  16. b.putParcelable("laststate", new SaveMe());
  17. onSaveInstanceState(b);
  18. }
  19. }
  20. class SaveMe implements Parcelable {
  21. static final int test = 1234;
  22. private int user;
  23. private String name;
  24. private double score;
  25. private SaveMeToo smt;
  26. public void writeToParcel(Parcel out, int flags) {
  27. out.writeInt(user);
  28. out.writeString(name);
  29. out.writeDouble(score);
  30. out.writeParcelable(smt, flags);
  31. }
  32. public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
  33. public SaveMe createFromParcel(Parcel in) { return new SaveMe(in); }
  34. public SaveMe[] newArray(int size) { return new SaveMe[size]; }
  35. };
  36. private SaveMe(Parcel in) {
  37. user = in.readInt();
  38. name = in.readString();
  39. score = in.readDouble();
  40. smt = in.readParcelable(getClass().getClassLoader());
  41. }
  42. public SaveMe() {}
  43. public int describeContents() { return 0; }
  44. }
  45. class SaveMeToo implements Parcelable {
  46. private int moo;
  47. public void writeToParcel(Parcel out, int flags) {
  48. out.writeInt(moo);
  49. }
  50. public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
  51. public SaveMeToo createFromParcel(Parcel in) { return new SaveMeToo(in); }
  52. public SaveMeToo[] newArray(int size) { return new SaveMeToo[size]; }
  53. };
  54. private SaveMeToo(Parcel in) {
  55. moo = in.readInt();
  56. }
  57. public int describeContents() { return 0; }
  58. }
Parsed in 0.200 seconds, using GeSHi 1.0.8.4


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics