2011-05-05 82 views
51

關於我的代碼示例下來的時候如何序列化空值,如果一個Locable的變量爲null什麼shold怎麼辦?在例子中,現在如果l.getZoom()返回null,我得到了NullPointerException。使用Parcelable接口

@Override 
public void writeToParcel(Parcel parcel, int arg1) { 
    parcel.writeInt(count); 
    for(Locable l:locableArr){ 
     parcel.writeInt(l.getOriginId()); 
     parcel.writeInt(l.getLocableType()); 
     parcel.writeInt(l.getZoom()); 
     parcel.writeDouble(l.getLatituda()); 
     parcel.writeDouble(l.getLongituda()); 
     parcel.writeString(l.getTitle()); 
     parcel.writeString(l.getSnipet()); 
    } 

} 

謝謝!

+0

看來NPE是自動拆箱的結果。可能我應該檢查空值並將其設置爲0? – 2011-05-05 23:26:30

+0

如果變焦已經值0+,考慮較空爲-1 – JAL 2011-05-05 23:29:16

+0

現在我在做類似的事情,如果值是NULL我寫了一些值,-1或空字符串,我反序列化設置爲NULL時我。醜陋的...我想如果有人能證實這是對的,我會更滿意我的代碼。 – 2011-05-25 10:10:49

回答

13
,我已經看到

大多數序列化代碼使用任一標誌來指示存在/不存在的值的OR先用計數字段的值(例如,書寫陣列時),其中計數字段正好被設置到零,如果該值根本不存在。

檢查的Android核心類的源代碼揭示了這樣的代碼(來自消息類別):

if (obj != null) { 
     try { 
      Parcelable p = (Parcelable)obj; 
      dest.writeInt(1); 
      dest.writeParcelable(p, flags); 
     } catch (ClassCastException e) { 
      throw new RuntimeException(
       "Can't marshal non-Parcelable objects across processes."); 
     } 
    } else { 
     dest.writeInt(0); 
    } 

或該(從意圖類):

if (mCategories != null) { 
     out.writeInt(mCategories.size()); 
     for (String category : mCategories) { 
      out.writeString(category); 
     } 
    } else { 
     out.writeInt(0); 
    } 

我的建議:在你的代碼,如果有「放大== NULL」和「縮放== 0」的功能沒有差異,那麼我只需要聲明變焦作爲原始(int,而不是Integer),或在constructo其初始化爲零r並確保你永遠不會將它設置爲null(那麼你可以保證它永遠不會爲null,並且你不必在你的序列化/反序列化方法中添加特殊的代碼來處理它)。

91

可以使用Parcel.writeValue編組通用對象與空值。

+42

並讀取數值... s =(String)in.readValue(String.class.getClassLoader()); – 2013-01-10 20:08:12

+0

太棒了!謝謝。 – tasomaniac 2014-03-20 09:37:05

+2

@SofiSoftwareLLC查看parcel.readValue的源代碼,只需要類型爲Map,Parcelable,ArrayList,Object []和Parcelable []的類加載器。對於其他類型,您可以爲類加載器傳入null。 https://開頭github上。com/android/platform_frameworks_base/blob/3bdbf644d61f46b531838558fabbd5b990fc4913/core/java/android/os/Parcel.java#L2002 – miguel 2015-02-04 18:52:51

10

這是我想出了安全地寫字符串的解決方案:

private void writeStringToParcel(Parcel p, String s) { 
    p.writeByte((byte)(s != null ? 1 : 0)); 
    p.writeString(s); 
} 

private String readStringFromParcel(Parcel p) { 
    boolean isPresent = p.readByte() == 1; 
    return isPresent ? p.readString() : null; 
} 
+0

我在複製並粘貼代碼後遇到了一些麻煩,沒有意識到在readStringFromParcel() 1與字節進行比較,然後將其與p.readByte()進行比較。最後我選擇了「p.writeInt((s!= null?1:0));」和「boolean isPresent = p.readInt()== 1;」 – Matt 2013-04-21 17:53:54

+3

只有當它不是null時,你才應該使用'p.writeString(s)'行來寫字符串。否則在這一行你會得到一個NullPointerException。 – Price 2014-07-18 06:13:11

+0

如果您使用的是'p.writeParcelable'而不是'p.writeString',那麼您不會立即得到NullPointerException,稍後會由於未對齊的讀取和寫入序列而導致出現一些陰影式的ClassCastException。如果該對象不爲null,則只應寫入對象。 – Roland 2018-02-21 16:21:27

11

我使用的是Parcelable類具有IntegerBoolean領域以及和這些字段可以爲空。

我在使用通用Parcel.writeValue方法時遇到了問題,特別是當我試圖通過Parcel.readValue將其讀回時。我不斷得到一個運行時異常,說它無法找出parceled對象的類型。

最終,我還是能夠通過使用Parcel.writeSerializableParcel.readSerializable用類型轉換來解決這個問題,因爲這兩個IntegerBoolean實現Serializable接口。讀取和寫入方法爲您處理null值。

+0

這實際上有效。 – 2017-02-08 11:34:31