是否有可能创建一个HashMap是Parcelable在Android?有可能、创建一个、HashMap、Parcelable

2023-09-04 06:30:04 作者:非爱不可

我想HashMap的延伸作为Parcelable和我然而,编制,语法,在运行时,它抛出一个异常,并返回一个空指针试图取消元帅的数据。

发送者具有投给(Parcelable)来解决多义性,但是,接收机抱怨预计Parcelable但发现HashMap中。

任何人都已经成功的呢? 是我的语法错误? 有没有更好的解决办法?

以下是code:

HomeActivity.java - 发件人 ContentViewActivity.java - 接收器 在ContentItemSimple.java - 正如它的名字 意味着(包装一个String和Integer) ContentItemCollection.java - 这是 HashMap中

HomeActivity.java

 包com.mobibob.android.studyparceable;

进口的java.util.HashMap;

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

公共类HomeActivity扩展活动实现OnClickListener {
    私有静态最后字符串变量=HomeActivity;
    私人ContentItemSimple mContentItemSimple = NULL;
    私人ContentItemContainer mContentItemContainer = NULL;

    / **第一次创建活动时调用。 * /
    @覆盖
    公共无效的onCreate(包savedInstanceState){
        super.onCreate(savedInstanceState);
        的setContentView(R.layout.home);

        按钮点击=(按钮)findViewById(R.id.button_clickit);
        click.setOnClickListener(本);

        mContentItemSimple =新ContentItemSimple();
        mContentItemSimple.name =mobibob;
        mContentItemSimple.year = 2010;

        字符串值=值;
        时间nowTime =新时代();
        nowTime.setToNow();
        mContentItemContainer =新ContentItemContainer();
        mContentItemContainer.put(字符串,新的String(棒球是伟大的!));
        mContentItemContainer.put(整数,新的整数(1234));
// mContentItemContainer.put(布尔,新的布尔值(true));
// mContentItemContainer.put(日期,nowTime);
// mContentItemContainer.put(包裹,新包());
        Log.d(TAG,.....+ mContentItemContainer.toString());
    }

    @覆盖
    公共无效的onClick(视图v){

        意图I =新的意图(getBaseContext(),ContentViewActivity.class);
        i.putExtra(ContentItemSimple.EXTRA_CONTENT_DETAIL,mContentItemSimple);
        i.putExtra(ContentItemContainer.EXTRA_CONTENT_CONTAINER,(Parcelable)mContentItemContainer);
        startActivityForResult(ⅰ,0);

    }
}
 

ContentViewActivity

 包com.mobibob.android.studyparceable;

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

进口com.mobibob.android.studyparceable.ContentItemSimple;

公共类ContentViewActivity扩展活动实现OnClickListener {

    私有静态最后字符串变量=ContentViewActivity;

    @覆盖
    保护无效的onCreate(包savedInstanceState){
        super.onCreate(savedInstanceState);

        的setContentView(R.layout.content_view);

        按钮GOHOME =(按钮)findViewById(R.id.button_gohome);

        gohome.setOnClickListener(本);

        ContentItemSimple CI = NULL;
        ContentItemContainer CX = NULL;

        尝试 {
            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));

        }赶上(例外五){
            Log.e(TAG,e.toString());
            e.printStackTrace();
        }
    }

    @覆盖
    公共无效的onClick(视图v){
        完();
    }

}
 

ContentItemSimple.java

 包com.mobibob.android.studyparceable;

进口android.os.Parcel;
进口android.os.Parcelable;
进口android.util.Log;

公共类ContentItemSimple实现Parcelable {
        公共静态最终字符串变量=ContentItem;
    公共静态最后弦乐EXTRA_CONTENT_DETAIL =contentDetail;
    公共字符串名称=名称;
    公共整数年= Integer.MIN_VALUE的;

    ContentItemSimple(){
        NAME =新的String();
        一年=新的整数(Integer.MIN_VALUE的);
    }

    ContentItemSimple(包裹的){
            尝试 {
                名称= in.readString();
                年= in.readInt();
            }赶上(例外五){
                Log.e(TAG,e.toString());
                e.printStackTrace();
        }
    }

    @覆盖
    公共字符串的toString(){
        返回的String.Format(NAME =%年龄=%D,名称,年份);
    }

    @覆盖
    公众诠释describeContents(){
        返回0;
    }

    @覆盖
    公共无效writeToParcel(包裹DEST,INT标志){
        dest.writeString(名称);
        dest.writeInt(一年);
    }

    公共静态最终Parcelable.Creator< ContentItemSimple> CREATOR =新Parcelable.Creator< ContentItemSimple>(){
        公共ContentItemSimple createFromParcel(包裹中){
        返回新ContentItemSimple(中);
        }

        公共ContentItemSimple [] newArray(INT尺寸){
        返回新ContentItemSimple【尺寸】;
        }
    };

}
 
关于HashMap

ContentItemContainer.java

 包com.mobibob.android.studyparceable;

进口的java.util.HashMap;
进口java.util.Iterator的;

进口android.os.Parcel;
进口android.os.Parcelable;

公共类ContentItemContainer延伸的HashMap<字符串,对象>实现Parcelable {
    / **
     *集装箱的WDDX'结构'的元素。
     * /
    私有静态最后长的serialVersionUID = 1L;
    ?//公共字符串名称=;
    ?//公共字符串值=;
    公共静态最后弦乐EXTRA_CONTENT_DETAIL =contentDetail;
    公共静态最后弦乐EXTRA_CONTENT_CONTAINER =contentContainer;
    公共静态最后弦乐EXTRA_CONTENTDETAIL_NAME =名;
    公共静态最后弦乐EXTRA_CONTENTDETAIL_VALUE =值;

//私有静态HashMap中<字符串,对象>图=新的HashMap<字符串,对象>();

    ContentItemContainer(){
        超();
    }

    ContentItemContainer(包裹的){
        in.readMap(此,ContentItemContainer.class.getClassLoader());
    }

    @覆盖
    公共字符串的toString(){
        StringBuilder的SB =新的StringBuilder();
        整数x = 0;
        迭代器< HashMap.Entry<字符串,对象>>它= this.entrySet()迭代器()。
        而(it.hasNext()){
            HashMap.Entry<字符串,对象>对=(HashMap.Entry<字符串,对象>)it.next();
            X ++;
            sb.append(\ N+ x.toString()+:)。.append(NAME =)追加(pairs.getKey())追加(VALUE =)追加(pairs.getValue。 ()的ToString());
        }
        返回sb.toString();
    }

    @覆盖
    公众诠释describeContents(){
        返回0;
    }

    @覆盖
    公共无效writeToParcel(包裹DEST,INT标志){
        dest.writeMap(本);
    }

    公共静态最终Parcelable.Creator< ContentItemContainer> CREATOR =新Parcelable.Creator< ContentItemContainer>(){
        公共ContentItemContainer createFromParcel(包裹中){
            返回新ContentItemContainer(中);
        }

        公共ContentItemContainer [] newArray(INT尺寸){
            返回新ContentItemContainer【尺寸】;
        }
    };

}
 

解决方案

类ContentItemContainer执行的方式 - 为延长HashMap中,你writeToParcel和Parcelable.Creator将永远不会被称为

的原因是,地图是被放在一个包裹有效的数据类型,因此,类被使用HashMap类的逻辑平坦化,不是你的。这是因为包的方式来实现,它会检查所提供的值是否为某些类别的后代在一个特定的顺序。

在unparcelling群众演员,一个HashMap会从你的对象的数据从而创建的。

要解决这个问题,你可以隐藏你的类中的HashMap和暴露的getter /推杆的HashMap中。这正是 ContentValues​​ 是实现以同样的方式,并瓜分/ unparcelling它的作品没有任何问题

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];
        }
    };

}

解决方案

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.