将可序列化对象转换为HashMap的衍生类

5

我正在尝试使用.putExtra()和sendBroadcast()将一些工作从IntentService发送到BroadcastReceiver,因此我有自己的类叫做"Message",它扩展了HashMap<String,String>并实现了Serializable接口。

public class Message extends HashMap<String,String> implements Serializable{
    public MessageID ID;
    public int Encode(byte[] buff,int off);
    public int Decode(byte[] buff,int off);
    //...
}

And I am sending it like this:

public static void ProcessMessage(Message msg) {
    Intent broadcastIntent = new Intent();
    broadcastIntent.setAction(Receiver.BROADCAST);
    broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
    broadcastIntent.putExtra("MESSAGE",(Serializable)msg);
    parentService.sendBroadcast(broadcastIntent);
    Print("Broadcasting intent to receiver ("+Receiver.BROADCAST+") from: "+parentService.toString());
}

这样接收:
public void onReceive(Context context, Intent intent) {
    Sys.Print("Receiver handling: "+intent.getAction());
    if(intent.getAction().equals(BROADCAST)){
        try {
            Message msg = (Message) intent.getSerializableExtra("MESSAGE");
            Sys.Print("Receiver handling " + msg.ID.toString());
        } catch(Exception ex){
            Sys.Print("Failed handling message, reason: "+ex.getStackTrace().toString());
        }
    }
}

但是我总是得到这个错误:"处理消息失败,原因:java.lang.ClassCastException: java.util.HashMap"

你有什么想法,可能出了什么问题吗?

堆栈跟踪:

com.myapp.Receiver.onReceive(Receiver.java:24)
android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:709)
android.os.Handler.handleCallback(Handler.java:587)
android.os.Handler.dispatchMessage(Handler.java:92)
android.os.Looper.loop(Looper.java:138)
android.app.ActivityThread.main(ActivityThread.java:3701)
java.lang.reflect.Method.invokeNative(Native Method)
java.lang.reflect.Method.invoke(Method.java:507)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:878)
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:636)
dalvik.system.NativeStart.main(Native Method)

如果有人遇到类似问题,我是这样解决的:

public class Message implements Parcelable {
    public HashMap<String,String> Data;
    public Message(){
        Data=new HashMap<>();
    }
    public int Encode(byte[] buff,int off);
    public int Decode(byte[] buff,int off);
    public void Add(String i,String v);
    public String At(String i);
    public boolean ContainsKey(String i);
    @Override
    public int describeContents() {
        return 0;
    }
    @Override
    public void writeToParcel(Parcel out, int flags) {
        out.writeMap(this.Data);
    }
    public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
        public Message createFromParcel(Parcel in) {
            return new Message(in);
        }
        public Message[] newArray(int size) {
            return new Message[size];
        }
    };
    public Message(Parcel in) {
        Data=new HashMap<>();
        in.readMap(this.Data,String.class.getClassLoader());
    }
}

1
请放置整个堆栈跟踪。您在两侧使用相同的JVM吗? - Zielu
我直接在设备上运行它。 - user704565
2个回答

2
你不会喜欢这个答案。
Extras 存储在 Bundle 中。Android 对 Bundle 的内容进行了一些“优化”,如果它知道一个条目的类型,它会尝试智能地对其进行序列化/反序列化。因此,如果你把任何实现 Map 接口的东西放入 Bundle 中,当你再次取出来时,你将得到一个 HashMap :-(。
详细解释请参见 我对这个问题的回答
要解决你的问题,你需要让你的自定义类使用(包含)一个 HashMap 而不是继承一个 HashMap。

0

这是 Android SDK 中一个尚未修复的错误。在错误报告中,它是一个ArrayList,但它也适用于实现MapList的类。

在错误报告中,有人提出使用以下 holder 作为解决方法:

public class SerializableHolder implements Serializable {
    private Serializable content;
    public Serializable get() {
        return content;
    }
    public SerializableHolder(Serializable content) {
        this.content = content;
    }
}

但我的建议是改用Parcelable,它是专为Android设计的,比Serializable快得多。


现在我总是遇到一个问题,即getParcelableExtra("MESSAGE")始终返回null,而我使用broadcastIntent.putExtra("MESSAGE", (Parcelable) msg); - user704565
“bug”与实现Serializable无关。该bug与Android对实现MapList接口的类进行优化有关。请参阅我对这个问题的回答 - David Wasser
@DavidWasser,你的意思是实现Parcelable而不是Serializable不能解决它吗? - ddmps
@jakubinf 你是否实现了 Parcelable 所需的方法?请参考 https://dev59.com/9Gw05IYBdhLWcg3wiyRJ#7181792 - ddmps
不行。即使该类实现了 Parcelable 而不是 Serializable,任何试图从 Bundle 中获取该类的实例都将导致一个 HashMap - David Wasser
是的,即使我将HashMap<>和Parcelable结合在一起实现,Parcelable也从未调用实际的Message构造函数,并尝试调用不存在的HashMap构造函数,因此最好仅将HashMap用作成员,并将一些辅助方法实现到主类中。 - user704565

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接