java - 如果自定义类包含 HashMap 字段,则无法通过 Parcelable 传递自定义类 - 为什么?

标签 java android

我已经为我的自定义类实现了 Parcelable:

public class Tag implements Parcelable {
    int id;
    int type;
    int proficiencyLevel;
    HashMap<String, String> translations;

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

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(id);
        dest.writeInt(type);
        dest.writeInt(proficiencyLevel);

        // if this part is uncommented I get a NullPointerException
        /*
        dest.writeInt(translations.size());
        for (HashMap.Entry<String, String> entry : translations.entrySet()) {
            dest.writeString(entry.getKey());
            dest.writeString(entry.getValue());
        }
        */
    }

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

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

    private Tag(Parcel in) {
        id = in.readInt();
        type = in.readInt();
        proficiencyLevel = in.readInt();

        // I've put breakpoint here and it seems to work OK, but then I get a NullPointerException
        // deserialize `translations` field
        /*int size = in.readInt();
        for (int i = 0; i < size; i++) {
            String key = in.readString();
            String value = in.readString();
            translations.put(key, value);
        }*/
    }
}

现在我从 Activity A 中传递它:

Tag[] tagsList = new Gson().fromJson(tags, Tag[].class);
Intent activityTagsSelectorLauncher = new Intent(this, ActivityTagsSelector.class);
activityTagsSelectorLauncher.putParcelableArrayListExtra("tagsList", new ArrayList<>(Arrays.asList(tagsList)));
startActivityForResult(activityTagsSelectorLauncher, SELECT_TAGS_REQUEST);

并在 Activity B 中像这样接收它:

ArrayList<Tag> tagsList = getIntent().getParcelableArrayListExtra("tagsList");

如果我不写 HashMap<String, String> translations 一切正常 field 。我得到NullPointerException当 Activity B开始时。我已在构造函数 private Tag(Parcel in) { 中放置断点似乎一切正常,所以我不明白我做错了什么。

最佳答案

你得到 NPE ,因为您没有初始化翻译 Map :

HashMap<String, String> translations

就像

HashMap<String, String> translations = null;

更改声明并初始化 map :

HashMap<String, String> translations = new HashMap<String, String>();

取消注释后即可使用它

dest.writeInt(translations.size());
for (HashMap.Entry<String, String> entry : translations.entrySet()) {
    dest.writeString(entry.getKey());
    dest.writeString(entry.getValue());
}

更新:为了澄清发生的情况,您声明了变量但没有初始化它,所以 JVM确实如此,并翻译成 HashMap<String, String> translations = null .

Initial Values of Variables

Every variable in a program must have a value before its value is used:

Each class variable, instance variable, or array component is initialized with a default value when it is created

[...] For all reference types, the default value is null.

看一下这个默认初始化表:

Type        Default Value
---------   -------------
boolean     false
byte        (byte) 0
short       (short) 0
int         0
long        0L
char        \u0000
float       0.0f
double      0.0d
object      null         <-------------- YAY!

之后,当您尝试使用 translations.size() 获取尺寸时与 null.size() 相同,有你的 NPE ...

更大代码中的另一个场景是您可能不想初始化 translations ,这样您就可以safe-check你的句子:

dest.writeInt(translations != null ? translation.size() : 0);

有关更多信息,请查看 here , here ,和HERE

关于java - 如果自定义类包含 HashMap 字段,则无法通过 Parcelable 传递自定义类 - 为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30345007/

相关文章:

java - 显示音频信号

java - 按下按钮时更改 JLabel

java - 谷歌地图从异步任务 onPostExecute 在 Canvas 上叠加绘图

java - 我们如何访问多维数组

java - 如何让计时器在后台运行以在一定时间后执行操作?

java - 如何在java中添加 protected 变量

android - 如何使用 StartActivityForResult()

java - 减少数组的大小(通过创建新数组) - arrayList 是如何做到的?

java - 应用程序需要 13 秒才能显示启动屏幕

Android如何删除html字符串中的特定数据?