2010-08-23 75 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

相关问题