2015-04-12 2 views
3

J'essaye d'envoyer un travail de IntentService à BroadcastReceiver en utilisant .putExtra() et sendBroadcast(), donc j'ai ma propre classe appelée "Message", qui étend HashMap < String, String > et implémente Serializable.Casting Serilizable à la dérivation de HashMap

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); 
    //... 
} 

Et je l'envoie comme ceci:

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

Et recevoir comme ceci:

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

Mais ici, je reçois toujours ceci: "Failed handling message, reason: java.lang.ClassCastException: java.util.HashMap"

Toute idée de ce qui pourrait se tromper?

Stack trace:

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) 

Donc finalement, si quelqu'un avait le même problème, je l'ai résolu comme ceci:

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

lieu toute stacktrace s'il vous plaît utilisez-vous la même machine virtuelle Java sur.. les deux côtés? – Zielu

+0

Je l'exécute directement sur l'appareil. – jakubinf

Répondre

1

Vous n'aimez pas la réponse. Les options sont stockées dans un Bundle. Android fait quelques "optimisations" sur le contenu de Bundle s et il essaie d'être intelligent sur la façon de sérialiser/désérialiser une entrée si elle connaît son type. Donc, si vous mettez quelque chose qui implémente l'interface Map en Bundle, lorsque vous récupérerez sur vous aurez une HashMap :-(

Voir my answer to this question pour une explication détaillée de la mécanique.

Pour résoudre votre problème , vous aurez besoin d'avoir votre classe personnalisée utilisation (ex: contenir) un HashMap et non être (c.-à hériter de) un HashMap

1

Ceci est un bug (encore, pas fixe) dans le SDK Android. Dans le bug report, il s'agit d'un ArrayList, mais il s'applique également aux classes qui implémentent Map ou List.

Dans le rapport de bogue, quelqu'un a proposé d'utiliser le support suivant comme solution:

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

mais ma suggestion serait plutôt d'implémenter Parcelable, qui est fait pour Android et est beaucoup plus rapide que Serializable.

+0

Maintenant je cours toujours, que getParcelableExtra ("MESSAGE") renvoie toujours null, et je fais 'broadcastIntent.putExtra (" MESSAGE ", (Parcelable) msg);' – jakubinf

+0

Le "bug" n'a rien à voir avec l'implémentation 'Serializable '. Le bug est lié aux optimisations Android pour les classes qui implémentent les interfaces 'Map' ou' List'. Voir [ma réponse à cette question.] (Http://stackoverflow.com/a/12305459/769265) –

+0

@DavidWasser Donc, vous dites que l'implémentation de 'Parcelable' au lieu de' Serializable' ne le résoudra pas? – ddmps