是否可以在 Android 上创建一个 Parcelable 的 HashMap? [英] Is it possible to create a HashMap that is Parcelable on Android?

查看:21
本文介绍了是否可以在 Android 上创建一个 Parcelable 的 HashMap?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将 HashMap 扩展为 Parcelable,并且我获得了要编译的语法,但是,在运行时它会引发异常并返回一个空指针,试图解组数据.

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.

发送者必须强制转换为 (Parcelable) 来解决歧义,但是接收者抱怨说应该是 Parcelable 但找到了 HashMap.

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?

以下是代码:

  • HomeActivity.java - 发送者
  • ContentViewActivity.java - 接收者
  • ContentItemSimple.java - 作为它的名字暗示(包装一个字符串和整数)
  • ContentItemCollection.java - 这是HashMap

HomeActivity.java

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);

    }
}

内容视图活动

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

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

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("
"+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];
        }
    };

}

推荐答案

你的类 ContentItemContainer 的实现方式——作为扩展 HashMap,你的 writeToParcel 和 Parcelable.Creator 永远不会被调用.

The way your class ContentItemContainer is implemented - as extending HashMap, your writeToParcel and Parcelable.Creator will never be called.

原因是 Map 是要放入 Parcel 中的有效数据类型,因此该类使用 HashMap 类的逻辑而不是您的逻辑扁平化.这是因为 Parcel 的实现方式,它会检查提供的值是否是按特定顺序的某些类的后代.

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.

当解包额外内容时,将根据您的对象数据创建一个 HashMap.

When unparcelling the extras, a HashMap will be created from your object's data consequently.

要解决这个问题,您可以在类中隐藏 HashMap,并为 HashMap 公开 getter/putter.这与 ContentValues 的实现方式和 parcelling/unparcelling 完全相同它可以正常工作.

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.

这篇关于是否可以在 Android 上创建一个 Parcelable 的 HashMap?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆