欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android中Serializable和Parcelable序列化對(duì)象詳解

 更新時(shí)間:2016年02月24日 09:52:42   作者:Darker  
這篇文章主要介紹了Android中Serializable和Parcelable序列化對(duì)象的相關(guān)資料,感興趣的小伙伴們可以參考一下

本文詳細(xì)對(duì)Android中Serializable和Parcelable序列化對(duì)象進(jìn)行學(xué)習(xí),具體內(nèi)容如下

學(xué)習(xí)內(nèi)容:

1.序列化的目的

2.Android中序列化的兩種方式

3.Parcelable與Serializable的性能比較

4.Android中如何使用Parcelable進(jìn)行序列化操作

5.Parcelable的工作原理

6.相關(guān)實(shí)例

 1.序列化的目的

 1).永久的保存對(duì)象數(shù)據(jù)(將對(duì)象數(shù)據(jù)保存在文件當(dāng)中,或者是磁盤中

  2).通過序列化操作將對(duì)象數(shù)據(jù)在網(wǎng)絡(luò)上進(jìn)行傳輸(由于網(wǎng)絡(luò)傳輸是以字節(jié)流的方式對(duì)數(shù)據(jù)進(jìn)行傳輸?shù)?因此序列化的目的是將對(duì)象數(shù)據(jù)轉(zhuǎn)換成字節(jié)流的形式)

  3).將對(duì)象數(shù)據(jù)在進(jìn)程之間進(jìn)行傳遞(Activity之間傳遞對(duì)象數(shù)據(jù)時(shí),需要在當(dāng)前的Activity中對(duì)對(duì)象數(shù)據(jù)進(jìn)行序列化操作.在另一個(gè)Activity中需要進(jìn)行反序列化操作講數(shù)據(jù)取出)

  4).Java平臺(tái)允許我們?cè)趦?nèi)存中創(chuàng)建可復(fù)用的Java對(duì)象,但一般情況下,只有當(dāng)JVM處于運(yùn)行時(shí),這些對(duì)象才可能存在,即,這些對(duì)象的生命周期不會(huì)比JVM的生命周期更長(zhǎng)(即每個(gè)對(duì)象都在JVM中)但在現(xiàn)實(shí)應(yīng)用中,就可能要停止JVM運(yùn)行,但有要保存某些指定的對(duì)象,并在將來重新讀取被保存的對(duì)象。這是Java對(duì)象序列化就能夠?qū)崿F(xiàn)該功能。(可選擇入數(shù)據(jù)庫(kù)、或文件的形式保存)

  5).序列化對(duì)象的時(shí)候只是針對(duì)變量進(jìn)行序列化,不針對(duì)方法進(jìn)行序列化.

  6).在Intent之間,基本的數(shù)據(jù)類型直接進(jìn)行相關(guān)傳遞即可,但是一旦數(shù)據(jù)類型比較復(fù)雜的時(shí)候,就需要進(jìn)行序列化操作了.

2.Android中實(shí)現(xiàn)序列化的兩種方式
1).Implements Serializable 接口 (聲明一下即可)
Serializable 的簡(jiǎn)單實(shí)例:

public class Person implements Serializable{
 private static final long serialVersionUID = -7060210544600464481L;
 private String name;
 private int age;
 
 public String getName(){
  return name;
 }
 
 public void setName(String name){
  this.name = name;
 }
 
 public int getAge(){
  return age;
 }
 
 public void setAge(int age){
  this.age = age;
 }
}

2).Implements Parcelable 接口(不僅僅需要聲明,還需要實(shí)現(xiàn)內(nèi)部的相應(yīng)方法)
Parcelable的簡(jiǎn)單實(shí)例:

注:寫入數(shù)據(jù)的順序和讀出數(shù)據(jù)的順序必須是相同的.

public class Book implements Parcelable{
 private String bookName;
 private String author;
 private int publishDate;
 
 public Book(){
  
 }
 
 public String getBookName(){
  return bookName;
 }
 
 public void setBookName(String bookName){
  this.bookName = bookName;
 }
 
 public String getAuthor(){
  return author;
 }
 
 public void setAuthor(String author){
  this.author = author;
 }
 
 public int getPublishDate(){
  return publishDate;
 }
 
 public void setPublishDate(int publishDate){
  this.publishDate = publishDate;
 }
 
 @Override
 public int describeContents(){
  return 0;
 }
 
 @Override
 public void writeToParcel(Parcel out, int flags){
  out.writeString(bookName);
  out.writeString(author);
  out.writeInt(publishDate);
 }
 
 public static final Parcelable.Creator<Book> CREATOR = new Creator<Book>(){
  
     @Override
  public Book[] newArray(int size){
   return new Book[size];
  }
  
  @Override
  public Book createFromParcel(Parcel in){
   return new Book(in);
  }
 };
 
 public Book(Parcel in){
  //如果元素?cái)?shù)據(jù)是list類型的時(shí)候需要: lits = new ArrayList<?> in.readList(list); 否則會(huì)出現(xiàn)空指針異常.并且讀出和寫入的數(shù)據(jù)類型必須相同.如果不想對(duì)部分關(guān)鍵字進(jìn)行序列化,可以使用transient關(guān)鍵字來修飾以及static修飾.
  bookName = in.readString();
  author = in.readString();
  publishDate = in.readInt();
 }
}

  我們知道在Java應(yīng)用程序當(dāng)中對(duì)類進(jìn)行序列化操作只需要實(shí)現(xiàn)Serializable接口就可以,由系統(tǒng)來完成序列化和反序列化操作,但是在Android中序列化操作有另外一種方式來完成,那就是實(shí)現(xiàn)Parcelable接口.也是Android中特有的接口來實(shí)現(xiàn)類的序列化操作.原因是Parcelable的性能要強(qiáng)于Serializable.因此在絕大多數(shù)的情況下,Android還是推薦使用Parcelable來完成對(duì)類的序列化操作的.

3.Parcelable與Serializable的性能比較

首先Parcelable的性能要強(qiáng)于Serializable的原因我需要簡(jiǎn)單的闡述一下

  1). 在內(nèi)存的使用中,前者在性能方面要強(qiáng)于后者

  2). 后者在序列化操作的時(shí)候會(huì)產(chǎn)生大量的臨時(shí)變量,(原因是使用了反射機(jī)制)從而導(dǎo)致GC的頻繁調(diào)用,因此在性能上會(huì)稍微遜色

  3). Parcelable是以Ibinder作為信息載體的.在內(nèi)存上的開銷比較小,因此在內(nèi)存之間進(jìn)行數(shù)據(jù)傳遞的時(shí)候,Android推薦使用Parcelable,既然是內(nèi)存方面比價(jià)有優(yōu)勢(shì),那么自然就要優(yōu)先選擇.

  4). 在讀寫數(shù)據(jù)的時(shí)候,Parcelable是在內(nèi)存中直接進(jìn)行讀寫,而Serializable是通過使用IO流的形式將數(shù)據(jù)讀寫入在硬盤上.

  但是:雖然Parcelable的性能要強(qiáng)于Serializable,但是仍然有特殊的情況需要使用Serializable,而不去使用Parcelable,因?yàn)镻arcelable無(wú)法將數(shù)據(jù)進(jìn)行持久化,因此在將數(shù)據(jù)保存在磁盤的時(shí)候,仍然需要使用后者,因?yàn)榍罢邿o(wú)法很好的將數(shù)據(jù)進(jìn)行持久化.(原因是在不同的Android版本當(dāng)中,Parcelable可能會(huì)不同,因此數(shù)據(jù)的持久化方面仍然是使用Serializable)

  速度測(cè)試:

  測(cè)試方法:

1)、通過將一個(gè)對(duì)象放到一個(gè)bundle里面然后調(diào)用Bundle#writeToParcel(Parcel, int)方法來模擬傳遞對(duì)象給一個(gè)activity的過程,然后再把這個(gè)對(duì)象取出來。

2)、在一個(gè)循環(huán)里面運(yùn)行1000 次。

3)、兩種方法分別運(yùn)行10次來減少內(nèi)存整理,cpu被其他應(yīng)用占用等情況的干擾。

4)、參與測(cè)試的對(duì)象就是上面的相關(guān)代碼

5)、在多種Android軟硬件環(huán)境上進(jìn)行測(cè)試

  • LG Nexus 4 – Android 4.2.2
  • Samsung Nexus 10 – Android 4.2.2
  • HTC Desire Z – Android 2.3.3 

 結(jié)果如圖:

 

 性能差異:

Nexus 10

Serializable: 1.0004ms,  Parcelable: 0.0850ms – 提升10.16倍。

Nexus 4

Serializable: 1.8539ms – Parcelable: 0.1824ms – 提升11.80倍。

Desire Z

Serializable: 5.1224ms – Parcelable: 0.2938ms – 提升17.36倍。

由此可以得出: Parcelable 比 Serializable快了10多倍。

  從相對(duì)的比較我們可以看出,Parcelable的性能要比Serializable要優(yōu)秀的多,因此在Android中進(jìn)行序列化操作的時(shí)候,我們需要盡可能的選擇前者,需要花上大量的時(shí)間去實(shí)現(xiàn)Parcelable接口中的內(nèi)部方法.

4.Android中如何使用Parcelable進(jìn)行序列化操作

說了這么多,我們還是來看看Android中如何去使用Parcelable實(shí)現(xiàn)類的序列化操作吧.
 Implements Parcelable的時(shí)候需要實(shí)現(xiàn)內(nèi)部的方法:

1).writeToParcel 將對(duì)象數(shù)據(jù)序列化成一個(gè)Parcel對(duì)象(序列化之后成為Parcel對(duì)象.以便Parcel容器取出數(shù)據(jù))

2).重寫describeContents方法,默認(rèn)值為0

3).Public static final Parcelable.Creator<T>CREATOR (將Parcel容器中的數(shù)據(jù)轉(zhuǎn)換成對(duì)象數(shù)據(jù)) 同時(shí)需要實(shí)現(xiàn)兩個(gè)方法:
  3.1 CreateFromParcel(從Parcel容器中取出數(shù)據(jù)并進(jìn)行轉(zhuǎn)換.)
  3.2 newArray(int size)返回對(duì)象數(shù)據(jù)的大小

 因此,很明顯實(shí)現(xiàn)Parcelable并不容易。實(shí)現(xiàn)Parcelable接口需要寫大量的模板代碼,這使得對(duì)象代碼變得難以閱讀和維護(hù)。具體的實(shí)例就是上面Parcelable的實(shí)例代碼.就不進(jìn)行列舉了.(有興趣的可以去看看Android中NetWorkInfo的源代碼,是關(guān)于網(wǎng)絡(luò)連接額外信息的一個(gè)相關(guān)類,內(nèi)部就實(shí)現(xiàn)了序列化操作.大家可以去看看)

5.Parcelable的工作原理

 無(wú)論是對(duì)數(shù)據(jù)的讀還是寫都需要使用Parcel作為中間層將數(shù)據(jù)進(jìn)行傳遞.Parcel涉及到的東西就是與C++底層有關(guān)了.都是使用JNI.在Java應(yīng)用層是先創(chuàng)建Parcel(Java)對(duì)象,然后再調(diào)用相關(guān)的讀寫操作的時(shí)候.就拿讀寫32為Int數(shù)據(jù)來說吧:

static jint android_os_Parcel_readInt(JNIEnv* env, jobject clazz){
 Parcel* parcel = parcelForJavaObject(env, clazz);
 if (parcel != NULL) {
  return parcel->readInt32();
 }
 return 0;
}

調(diào)用的方法就是這個(gè)過程,首先是將Parcel(Java)對(duì)象轉(zhuǎn)換成Parcel(C++)對(duì)象,然后被封裝在Parcel中的相關(guān)數(shù)據(jù)由C++底層來完成數(shù)據(jù)的序列化操作.

status_t Parcel::writeInt32(int32_t val){
 return writeAligned(val);
} 
template<class t="">
status_t Parcel::writeAligned(T val) {
 COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T));
 
 if ((mDataPos+sizeof(val)) <= mDataCapacity) {
restart_write:
  *reinterpret_cast<t*>(mData+mDataPos) = val;
  return finishWrite(sizeof(val));
 }
 
 status_t err = growData(sizeof(val));
 if (err == NO_ERROR) goto restart_write;
 return err;
}
真正的讀寫過程是由下面的源代碼來完成的.
status_t Parcel::continueWrite(size_t desired)
{
 // If shrinking, first adjust for any objects that appear
 // after the new data size.
 size_t objectsSize = mObjectsSize;
 if (desired < mDataSize) {
  if (desired == 0) {
   objectsSize = 0;
  } else {
   while (objectsSize > 0) {
    if (mObjects[objectsSize-1] < desired)
     break;
    objectsSize--;
   }
  }
 }
 
 if (mOwner) {
  // If the size is going to zero, just release the owner's data.
  if (desired == 0) {
   freeData();
   return NO_ERROR;
  }

  // If there is a different owner, we need to take
  // posession.
  uint8_t* data = (uint8_t*)malloc(desired);
  if (!data) {
   mError = NO_MEMORY;
   return NO_MEMORY;
  }
  size_t* objects = NULL;
  
  if (objectsSize) {
   objects = (size_t*)malloc(objectsSize*sizeof(size_t));
   if (!objects) {
    mError = NO_MEMORY;
    return NO_MEMORY;
   }

   // Little hack to only acquire references on objects
   // we will be keeping.
   size_t oldObjectsSize = mObjectsSize;
   mObjectsSize = objectsSize;
   acquireObjects();
   mObjectsSize = oldObjectsSize;
  }
  
  if (mData) {
   memcpy(data, mData, mDataSize < desired ? mDataSize : desired);
  }
  if (objects && mObjects) {
   memcpy(objects, mObjects, objectsSize*sizeof(size_t));
  }
  //ALOGI("Freeing data ref of %p (pid=%d)\n", this, getpid());
  mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);
  mOwner = NULL;

  mData = data;
  mObjects = objects;
  mDataSize = (mDataSize < desired) ? mDataSize : desired;
  ALOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
  mDataCapacity = desired;
  mObjectsSize = mObjectsCapacity = objectsSize;
  mNextObjectHint = 0;

 } else if (mData) {
  if (objectsSize < mObjectsSize) {
   // Need to release refs on any objects we are dropping.
   const sp<ProcessState> proc(ProcessState::self());
   for (size_t i=objectsSize; i<mObjectsSize; i++) {
    const flat_binder_object* flat
     = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);
    if (flat->type == BINDER_TYPE_FD) {
     // will need to rescan because we may have lopped off the only FDs
     mFdsKnown = false;
    }
    release_object(proc, *flat, this);
   }
   size_t* objects =
    (size_t*)realloc(mObjects, objectsSize*sizeof(size_t));
   if (objects) {
    mObjects = objects;
   }
   mObjectsSize = objectsSize;
   mNextObjectHint = 0;
  }

  // We own the data, so we can just do a realloc().
  if (desired > mDataCapacity) {
   uint8_t* data = (uint8_t*)realloc(mData, desired);
   if (data) {
    mData = data;
    mDataCapacity = desired;
   } else if (desired > mDataCapacity) {
    mError = NO_MEMORY;
    return NO_MEMORY;
   }
  } else {
   if (mDataSize > desired) {
    mDataSize = desired;
    ALOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
   }
   if (mDataPos > desired) {
    mDataPos = desired;
    ALOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);
   }
  }
  
 } else {
  // This is the first data. Easy!
  uint8_t* data = (uint8_t*)malloc(desired);
  if (!data) {
   mError = NO_MEMORY;
   return NO_MEMORY;
  }
  
  if(!(mDataCapacity == 0 && mObjects == NULL
    && mObjectsCapacity == 0)) {
   ALOGE("continueWrite: %d/%p/%d/%d", mDataCapacity, mObjects, mObjectsCapacity, desired);
  }
  
  mData = data;
  mDataSize = mDataPos = 0;
  ALOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
  ALOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);
  mDataCapacity = desired;
 }

 return NO_ERROR;
}

1).整個(gè)讀寫全是在內(nèi)存中進(jìn)行,主要是通過malloc()、realloc()、memcpy()等內(nèi)存操作進(jìn)行,所以效率比JAVA序列化中使用外部存儲(chǔ)器會(huì)高很多

2).讀寫時(shí)是4字節(jié)對(duì)齊的,可以看到#define PAD_SIZE(s) (((s)+3)&~3)這句宏定義就是在做這件事情

3).如果預(yù)分配的空間不夠時(shí)newSize = ((mDataSize+len)*3)/2;會(huì)一次多分配50%

4).對(duì)于普通數(shù)據(jù),使用的是mData內(nèi)存地址,對(duì)于IBinder類型的數(shù)據(jù)以及FileDescriptor使用的是mObjects內(nèi)存地址。后者是通過flatten_binder()和unflatten_binder()實(shí)現(xiàn)的,目的是反序列化時(shí)讀出的對(duì)象就是原對(duì)象而不用重新new一個(gè)新對(duì)象。
6.相關(guān)實(shí)例

最后上一個(gè)例子..

首先是序列化的類Book.class

public class Book implements Parcelable{
 private String bookName;
 private String author;
 private int publishDate;
 
 public Book(){
  
 }
 
 public String getBookName(){
  return bookName;
 }
 
 public void setBookName(String bookName){
  this.bookName = bookName;
 }
 
 public String getAuthor(){
  return author;
 }
 
 public void setAuthor(String author){
  this.author = author;
 }
 
 public int getPublishDate(){
  return publishDate;
 }
 
 public void setPublishDate(int publishDate){
  this.publishDate = publishDate;
 }
 
 @Override
 public int describeContents(){
  return 0;
 }
 
 @Override
 public void writeToParcel(Parcel out, int flags){
  out.writeString(bookName);
  out.writeString(author);
  out.writeInt(publishDate);
 }
 
 public static final Parcelable.Creator<Book> CREATOR = new Creator<Book>(){
  
     @Override
  public Book[] newArray(int size){
   return new Book[size];
  }
  
  @Override
  public Book createFromParcel(Parcel in){
   return new Book(in);
  }
 };
 
 public Book(Parcel in){
  //如果元素?cái)?shù)據(jù)是list類型的時(shí)候需要: lits = new ArrayList<?> in.readList(list); 否則會(huì)出現(xiàn)空指針異常.并且讀出和寫入的數(shù)據(jù)類型必須相同.如果不想對(duì)部分關(guān)鍵字進(jìn)行序列化,可以使用transient關(guān)鍵字來修飾以及static修飾.
  bookName = in.readString();
  author = in.readString();
  publishDate = in.readInt();
 }
}

第一個(gè)Activity,MainActivity

Book book = new Book();
book.setBookname("Darker");
book.setBookauthor("me");
book.setPublishDate(20);
Bundle bundle = new Bundle();
bundle.putParcelable("book", book);
Intent intent = new Intent(MainActivity.this,AnotherActivity.class);
intent.putExtras(bundle);

第二個(gè)Activity,AnotherActivity

Intent intent = getIntent();
Bundle bun = intent.getExtras();
Book book = bun.getParcelable("book");
System.out.println(book);

 總結(jié):Java應(yīng)用程序中有Serializable來實(shí)現(xiàn)序列化操作,Android中有Parcelable來實(shí)現(xiàn)序列化操作,相關(guān)的性能也作出了比較,因此在Android中除了對(duì)數(shù)據(jù)持久化的時(shí)候需要使用到Serializable來實(shí)現(xiàn)序列化操作,其他的時(shí)候我們?nèi)匀恍枰褂肞arcelable來實(shí)現(xiàn)序列化操作,因?yàn)樵贏ndroid中效率并不是最重要的,而是內(nèi)存,通過比較Parcelable在效率和內(nèi)存上都要優(yōu)秀與Serializable,盡管Parcelable實(shí)現(xiàn)起來比較復(fù)雜,但是如果我們想要成為一名優(yōu)秀的Android軟件工程師,那么我們就需要勤快一些去實(shí)現(xiàn)Parcelable,而不是偷懶與實(shí)現(xiàn)Serializable.當(dāng)然實(shí)現(xiàn)后者也不是不行,關(guān)鍵在于我們頭腦中的那一份思想。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助。

相關(guān)文章

  • Android應(yīng)用開發(fā)中RecyclerView組件使用入門教程

    Android應(yīng)用開發(fā)中RecyclerView組件使用入門教程

    這篇文章主要介紹了Android應(yīng)用開發(fā)中RecyclerView組件使用的入門教程,RecyclerView主要針對(duì)安卓5.0以上的material design開發(fā)提供支持,需要的朋友可以參考下
    2016-02-02
  • Android實(shí)現(xiàn)圖片反轉(zhuǎn)、翻轉(zhuǎn)、旋轉(zhuǎn)、放大和縮小

    Android實(shí)現(xiàn)圖片反轉(zhuǎn)、翻轉(zhuǎn)、旋轉(zhuǎn)、放大和縮小

    這篇文章主要介紹了Android實(shí)現(xiàn)圖片反轉(zhuǎn)、翻轉(zhuǎn)、旋轉(zhuǎn)、放大和縮小的相關(guān)代碼,需要的朋友可以參考下
    2015-09-09
  • Android中自定義控件之液位指示器

    Android中自定義控件之液位指示器

    這篇文章主要介紹了Android中自定義控件之液位指示器 方法的相關(guān)資料,需要的朋友可以參考下
    2016-03-03
  • 最新評(píng)論