2010-08-23 77 views
14

我試圖擴展HashMap作爲一個Parcelable,我得到了編譯的語法,但是,在運行時它會拋出一個異常並返回一個空指針試圖解除數據封送。是否有可能創建一個Android上的Parcelable的HashMap?

發件人必須轉換爲(Parcelable)來解決歧義,但是,接收方抱怨期望Parcelable但是找到了HashMap。

有沒有人用這個成功? 我的語法錯了嗎? 有更好的解決方案嗎?

以下是代碼:

  • HomeActivity.java - 發件人
  • ContentViewActivity.java - 接收機
  • ContentItemSimple.java - 正如它的名字暗示 (包裝一個字符串和整數)
  • ContentItemCollection.java - 這是 HashMap的

HomeActivity.java

package com.mobibob.android.studyparceable; 

import java.util.HashMap; 

import android.app.Activity; 
import android.content.Intent; 
import android.os.Bundle; 
import android.os.Parcel; 
import android.os.Parcelable; 
import android.text.format.Time; 
import android.util.Log; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.Button; 

public class HomeActivity extends Activity implements OnClickListener { 
    private static final String TAG = "HomeActivity"; 
    private ContentItemSimple mContentItemSimple = null; 
    private ContentItemContainer mContentItemContainer = null; 

    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.home); 

     Button click = (Button) findViewById(R.id.button_clickit); 
     click.setOnClickListener(this); 

     mContentItemSimple = new ContentItemSimple(); 
     mContentItemSimple.name = "mobibob"; 
     mContentItemSimple.year = 2010; 

     String value = "value"; 
     Time nowTime = new Time(); 
     nowTime.setToNow(); 
     mContentItemContainer = new ContentItemContainer(); 
     mContentItemContainer.put("string", new String("baseball is great!")); 
     mContentItemContainer.put("integer", new Integer(1234)); 
//  mContentItemContainer.put("boolean", new Boolean(true)); 
//  mContentItemContainer.put("date", nowTime); 
//  mContentItemContainer.put("parcel", new Bundle()); 
     Log.d(TAG, "..... " + mContentItemContainer.toString()); 
    } 

    @Override 
    public void onClick(View v) { 

     Intent i = new Intent(getBaseContext(), ContentViewActivity.class); 
     i.putExtra(ContentItemSimple.EXTRA_CONTENT_DETAIL, mContentItemSimple); 
     i.putExtra(ContentItemContainer.EXTRA_CONTENT_CONTAINER, (Parcelable) mContentItemContainer); 
     startActivityForResult(i, 0); 

    } 
} 

ContentViewActivity

package com.mobibob.android.studyparceable; 

import android.app.Activity; 
import android.os.Bundle; 
import android.util.Log; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.Button; 
import android.widget.TextView; 

import com.mobibob.android.studyparceable.ContentItemSimple; 

public class ContentViewActivity extends Activity implements OnClickListener { 

    private static final String TAG = "ContentViewActivity"; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     setContentView(R.layout.content_view); 

     Button gohome = (Button) findViewById(R.id.button_gohome); 

     gohome.setOnClickListener(this); 

     ContentItemSimple ci = null; 
     ContentItemContainer cx = null; 

     try { 
      ci = getIntent().getParcelableExtra(ContentItemSimple.EXTRA_CONTENT_DETAIL); 
      Log.i(TAG, "ci = " + ci.toString()); 

      cx = getIntent().getParcelableExtra(ContentItemContainer.EXTRA_CONTENT_CONTAINER); 
      Log.i(TAG, "cx = " + cx.toString()); 

      TextView tvName = (TextView) findViewById(R.id.ci_name); 
      tvName.setText(ci.name); 
      TextView tvYear = (TextView) findViewById(R.id.ci_year); 
      tvYear.setText(String.format("%d", ci.year)); 

     } catch (Exception e) { 
      Log.e(TAG, e.toString()); 
      e.printStackTrace(); 
     } 
    } 

    @Override 
    public void onClick(View v) { 
     finish(); 
    } 

} 

ContentItemSimple.java

package com.mobibob.android.studyparceable; 

import android.os.Parcel; 
import android.os.Parcelable; 
import android.util.Log; 

public class ContentItemSimple implements Parcelable { 
     public static final String TAG = "ContentItem"; 
    public static final String EXTRA_CONTENT_DETAIL = "contentDetail"; 
    public String name = "name"; 
    public Integer year = Integer.MIN_VALUE; 

    ContentItemSimple() { 
     name = new String(""); 
     year = new Integer(Integer.MIN_VALUE); 
    } 

    ContentItemSimple(Parcel in) { 
      try { 
       name = in.readString(); 
       year = in.readInt(); 
      } catch (Exception e) { 
       Log.e(TAG, e.toString()); 
       e.printStackTrace(); 
     } 
    } 

    @Override 
    public String toString() { 
     return String.format("name=%s age=%d", name, year); 
    } 

    @Override 
    public int describeContents() { 
     return 0; 
    } 

    @Override 
    public void writeToParcel(Parcel dest, int flags) { 
     dest.writeString(name); 
     dest.writeInt(year); 
    } 

    public static final Parcelable.Creator<ContentItemSimple> CREATOR = new Parcelable.Creator<ContentItemSimple>() { 
     public ContentItemSimple createFromParcel(Parcel in) { 
     return new ContentItemSimple(in); 
     } 

     public ContentItemSimple[] newArray(int size) { 
     return new ContentItemSimple[size]; 
     } 
    }; 

} 

ContentItemContainer.java

package com.mobibob.android.studyparceable; 

import java.util.HashMap; 
import java.util.Iterator; 

import android.os.Parcel; 
import android.os.Parcelable; 

public class ContentItemContainer extends HashMap<String, Object> implements Parcelable { 
    /** 
    * Container for wddx 'struct' elements. 
    */ 
    private static final long serialVersionUID = 1L; 
    // public String name = "?"; 
    // public String value = "?"; 
    public static final String EXTRA_CONTENT_DETAIL = "contentDetail"; 
    public static final String EXTRA_CONTENT_CONTAINER = "contentContainer"; 
    public static final String EXTRA_CONTENTDETAIL_NAME = "name"; 
    public static final String EXTRA_CONTENTDETAIL_VALUE = "value"; 

// private static HashMap<String, Object> map = new HashMap<String, Object>(); 

    ContentItemContainer() { 
     super(); 
    } 

    ContentItemContainer(Parcel in) { 
     in.readMap(this, ContentItemContainer.class.getClassLoader()); 
    } 

    @Override 
    public String toString() { 
     StringBuilder sb = new StringBuilder(""); 
     Integer x = 0; 
     Iterator<HashMap.Entry<String, Object>> it = this.entrySet().iterator(); 
     while (it.hasNext()) { 
      HashMap.Entry<String, Object> pairs = (HashMap.Entry<String, Object>) it.next(); 
      x++; 
      sb.append("\n"+x.toString()+": ").append("name=").append(pairs.getKey()).append(" value=").append(pairs.getValue().toString()); 
     } 
     return sb.toString(); 
    } 

    @Override 
    public int describeContents() { 
     return 0; 
    } 

    @Override 
    public void writeToParcel(Parcel dest, int flags) { 
     dest.writeMap(this); 
    } 

    public static final Parcelable.Creator<ContentItemContainer> CREATOR = new Parcelable.Creator<ContentItemContainer>() { 
     public ContentItemContainer createFromParcel(Parcel in) { 
      return new ContentItemContainer(in); 
     } 

     public ContentItemContainer[] newArray(int size) { 
      return new ContentItemContainer[size]; 
     } 
    }; 

} 
+2

爲什麼不使用'Bundle'而不是'HashMap'? – CommonsWare 2010-08-23 09:20:12

+0

我想到了,所以讓我切換,看看我是否得到我需要的東西。同時,這可以工作嗎?我知道該文檔指出,Parcelable並不打算成爲一個「通用」串行器,但我認爲這仍然在合理的使用範圍內。 – mobibob 2010-08-23 15:26:13

+1

切換到Bundle看起來像它會爲我的項目工作。同時,我想以目前的形式知道這個問題的答案。 (我相信這個答案對於Android操作系統及其SDK來說是很有啓發性的。) – mobibob 2010-08-23 19:38:21

回答

22

的方式類ContentItemContainer是實現 - 作爲擴展HashMap,你的writeToParcel和Parcelable.Creator將永遠不會被調用。

原因是Map是一個有效的數據類型被放在一個Parcel中,所以這個類被使用HashMap類的邏輯扁平化,而不是你的。這是因爲Parcel實現的方式,它會檢查提供的值是否是特定順序的特定類的後代。

如果沒有進行額外的細分處理,將會從對象的數據中創建一個HashMap。

要解決這個問題,你可以在你的類中隱藏HashMap,併爲HashMap公開getter/putters。這與ContentValues的實現方式完全相同,並且parcelling/unparcelling工作沒有任何問題。

+0

所以,幫我理解你的答案,你是說我的HashMap是作爲Map編寫的,然後試圖讀回爲HashMap,但是數據被確定爲Map,因此異常?這個異常不應該是'cast-exception'而不是'空指針異常'嗎? – mobibob 2010-08-31 03:03:13

+1

差不多。 Bundle試圖讀回Parcelable,但發現一個HashMap。 因此,一個CastException類在Bundle()內部發生,但它被捕獲,隨後Bundle在getParcelable()調用中返回null(Intent.getParcelableExtra是調用Intent.getExtras,然後是Bundle.getParcelable的快捷方式)。 – Thorstenvv 2010-08-31 08:44:00

+0

這一切都有道理,但我今天沒有時間來驗證。我假設你正在查看Android源代碼來回答我的問題,並且不能像黑盒一樣「調試它」,並按照人們可能期望的擴展和界面所暗示的那樣執行。我會接受你的回答,因爲時間不多了,我相信它會在你解釋的時候出現。 – mobibob 2010-08-31 19:39:06

相關問題