是否可以在 Android 上创建可 Parcelable 的 HashMap?
我试图将 HashMap 扩展为 Parcelable,并且获得了要编译的语法,但是,在运行时它会抛出异常并返回一个空指针,试图对数据进行解组。
发送者必须转换为 (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];
}
};
}
I am trying to extend HashMap as a Parcelable and I got the syntax to compile, however, at runtime it throws an exception and returns a null pointer trying to un-marshal the data.
The sender has to cast to (Parcelable) to resolve ambiguity, however, the receiver complains that is expected Parcelable but found HashMap.
Has anyone been successful with this?
Is my syntax wrong?
Is there a better solution?
Following is the code:
- HomeActivity.java - the sender
- ContentViewActivity.java - the receiver
- ContentItemSimple.java - as its name
implies (wraps a String and Integer) - ContentItemCollection.java - this is
the 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];
}
};
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
ContentItemContainer 类的实现方式 - 作为扩展 HashMap,您的 writeToParcel 和 Parcelable.Creator 将永远不会被调用。
原因是 Map 是放入 Parcel 中的有效数据类型,因此该类会使用 HashMap 类的逻辑(而不是您的逻辑)进行扁平化。这是因为 Parcel 的实现方式会检查提供的值是否是特定顺序的某些类的后代。
当解包额外内容时,将根据对象的数据创建一个 HashMap。
要解决此问题,您可以将 HashMap 隐藏在类中,并公开 HashMap 的 getters/putters。这与 ContentValues 的实现方式完全相同,并且打包/解包它工作没有任何问题。
The way your class ContentItemContainer is implemented - as extending HashMap, your writeToParcel and Parcelable.Creator will never be called.
The reason is that Map is a valid data type to be put in a Parcel, so that the class gets flattened using the logic of the HashMap class, and not yours. This is because the way Parcel is implemented, it checks whether the supplied values are descendants of certain classes in a specific order.
When unparcelling the extras, a HashMap will be created from your object's data consequently.
To work around this, you could hide the HashMap inside your class and expose getters/putters for the HashMap. This is exactly the same way that ContentValues is implemented, and parcelling/unparcelling it works without any problems.