Вопрос по service, exception, android, badparcelableexception – BadParcelableException: ClassNotFoundException при отмене сортировки

7

Я довольно новичок в Serializable и Parcelable. Мне трудно передать экземпляр этого объекта из приложения в удаленную службу:

public class Event implements Parcelable, Cloneable {

    /** Defines under what Bundle's key architecture events are stored */ 
    public static final String BUNDLE_KEY = "ZKEvent";

    /** Defines which messages are architecture's events */
    public static final int MSG_WHAT = 0xDEFECABE;

    /** Defines a key to store map under a Bundle to put into a Parcel (oh yeah!) */
    private static final String MAP_KEY = "MAP";

    /** Indicates this event ID. This ID should be the same in the event answer if any */
    private int idEvent = 0;

    /** Indicates this event priority */
    private int priority = EventPriority.EVENT_PRIORITY_LOW;

    /** ID for this event's sender */
    private int idSource = 0;

    /** ID for this event's destination */
    private int idDestination = 0;

    /** Action to be performed */
    private int action = EventAction.DEFAULT;

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

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

    /** 
     * Event's data
     * Represented as 
     *      key -> parameter;
     *      value -> data 
     */
    private Map<String, Object> data = new HashMap<String, Object>();

    /** Default constructor */
    public Event() {};

    /** Contructor with ID of the event */
    public Event(int id) {
        idEvent = id;
    }

    /** Constructor for Parcelable */
    public Event(Parcel in) {
        readFromParcel(in);
    }

    /** Gets event's priority */
    public int getPriority() {
        return priority;
    }

    /** Sets this event's priority */
    public void setPriority(int priority) {
        this.priority = priority;
    }

    /** Gets the ID of this event's sender */   
    public int getIdSource() {
        return idSource;
    }

    /** Sets the ID of this event's sender */
    public void setIdSource(int idSource) {
        this.idSource = idSource;
    }

    /** Gets the ID of this event's destination */
    public Integer getIdDestination() {
        return idDestination;
    }

    /** Sets the ID of this event's destination */
    public void setIdDestination(Integer idDestination) {
        this.idDestination = idDestination;
    }

    /** Gets the action of this event */
    public int getAction() {
        return action;
    }

    /** Sets the action of this event */
    public void setAction(int action) {
        this.action = action;
    }

    /** Gets the data of this event */
    public Object getData(String key) {
        return data.get(key);
    }

    /** Sets the data of this event  */
    public void addData(String key, Object data) {
        this.data.put(key, data);
    }

    /** Gets the ID of this event */
    public int getIdEvent() {
        return idEvent;
    }

    /** Sets the ID of this event */
    public void setIdEvent(int idEvent) {
        this.idEvent = idEvent;
    }

    @Override
    public Object clone() {

        Event clone = new Event();

        clone.action = this.action;
        clone.idDestination = this.idDestination;
        clone.idEvent = this.idEvent;
        clone.idSource = this.idSource;
        clone.priority = this.priority;

        for(Entry<String,Object> entry: this.data.entrySet()) {
            clone.data.put(entry.getKey(), entry.getValue());
        }

        return clone;
    }

    @Override
    public int describeContents() {
        // TODO Nothing here
        return 0;
    }

    @Override
    public void writeToParcel(Parcel out, int flags) {

        out.writeInt(idEvent);
        out.writeInt(priority);
        out.writeInt(idSource);
        out.writeInt(idDestination);
        out.writeInt(action);

        Bundle mapBundle = new Bundle();
        mapBundle.putSerializable(MAP_KEY, (Serializable) data);
    out.writeBundle(mapBundle);
    }

    /** Restoring this object from a Parcel */
    public void readFromParcel(Parcel in) {

        idEvent = in.readInt();
        priority = in.readInt();
        idSource = in.readInt();
        idDestination = in.readInt();
        action = in.readInt();

        Bundle mapBundle = in.readBundle();
        data = (Map<String, Object>) mapBundle.getSerializable(MAP_KEY);
    }
}

Поэтому я создаю новый экземпляр этого класса Event и передаю его службе следующим образом:

/** Register with service */
private void registerWithService() {
    Event registerEvent = EventFactory.getEvent();
    registerEvent.setAction(EventAction.REGISTER);
    registerEvent.setIdSource(1);

    Bundle data = new Bundle();
    data.putParcelable(Event.BUNDLE_KEY, registerEvent);

    Message msg = new Message();
    msg.setData(data); // Exception thrown here in the Service
    msg.what = Event.MSG_WHAT;
    try {
        outMessenger.send(msg);
    } catch (RemoteException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

А вот где в удаленной службе выдается исключение:

    public void handleMessage(Message msg) {
        if (msg.what == Event.MSG_WHAT) {
            // Get the data bundle
            Bundle bundle = msg.getData();
            // Extract the event from the message
            Event event = (Event) bundle.get(Event.BUNDLE_KEY); // Exception thrown here
            sendEvent(event);
        } else {
            Log.i(TAG, "Received non architecture message, dropping...");
        }
    }

И трассировка стека:

07-09 12:38:10.947: E/AndroidRuntime(2234): FATAL EXCEPTION: main
07-09 12:38:10.947: E/AndroidRuntime(2234): android.os.BadParcelableException: ClassNotFoundException when unmarshalling: com.blabla.android.core.event.Event
07-09 12:38:10.947: E/AndroidRuntime(2234):     at android.os.Parcel.readParcelable(Parcel.java:1958)
07-09 12:38:10.947: E/AndroidRuntime(2234):     at android.os.Parcel.readValue(Parcel.java:1846)
07-09 12:38:10.947: E/AndroidRuntime(2234):     at android.os.Parcel.readMapInternal(Parcel.java:2083)
07-09 12:38:10.947: E/AndroidRuntime(2234):     at android.os.Bundle.unparcel(Bundle.java:208)
07-09 12:38:10.947: E/AndroidRuntime(2234):     at android.os.Bundle.get(Bundle.java:260)
07-09 12:38:10.947: E/AndroidRuntime(2234):     at com.blabla.android.core.event.EventManager$EventHandler.handleMessage(EventManager.java:44)
07-09 12:38:10.947: E/AndroidRuntime(2234):     at android.os.Handler.dispatchMessage(Handler.java:99)
07-09 12:38:10.947: E/AndroidRuntime(2234):     at android.os.Looper.loop(Looper.java:123)
07-09 12:38:10.947: E/AndroidRuntime(2234):     at android.app.ActivityThread.main(ActivityThread.java:3683)
07-09 12:38:10.947: E/AndroidRuntime(2234):     at java.lang.reflect.Method.invokeNative(Native Method)
07-09 12:38:10.947: E/AndroidRuntime(2234):     at java.lang.reflect.Method.invoke(Method.java:507)
07-09 12:38:10.947: E/AndroidRuntime(2234):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
07-09 12:38:10.947: E/AndroidRuntime(2234):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
07-09 12:38:10.947: E/AndroidRuntime(2234):     at dalvik.system.NativeStart.main(Native Method)

Любая помощь с благодарностью, спасибо!

stackoverflow.com/questions/1996294/… Akram
@Akki: я прочитал этот ответ, но не знаю, что с этим делатьClassLoader позже ... Кроме того, зачем мне нужен отдельный ClassLoader, если этот класс включен в оба приложения? @Jules: этоremote сервис, так что это IPC. m0skit0
@Flow Вы имеете в виду, что другой вопрос является дубликатом этого ... m0skit0
Ваш сервис работает в том же процессе, что и создатель Bundle, который вы ему отправляете, или это межпроцессный запрос? Jules

Ваш Ответ

1   ответ
14

public void writeToParcel(Parcel out, int flags) {

    out.writeInt(idEvent);
    out.writeInt(priority);
    out.writeInt(idSource);
    out.writeInt(idDestination);
    out.writeInt(action);

    Bundle mapBundle = new Bundle();
    mapBundle.putSerializable(MAP_KEY, (Serializable) data);
   // You need to actually write the Bundle to the Parcel here...
}

EDIT Added additional solution to the ClassLoader problem:

Установите загрузчик классов вhandleMessage() в вашем удаленном сервисе вот так:

Bundle bundle = msg.getData();
bundle.setClassLoader(Event.class.getClassLoader());
Event event = (Event) bundle.get(Event.BUNDLE_KEY);
Я добавил его в Посылку, все то же исключение. Отредактировал вопрос. m0skit0
Хорошо, я действительно не знаю, почему вам нужно установить ClassLoader в этом случае. Очевидно, что тот, который установлен по умолчанию, не может видеть ваши классы (это, вероятно, System ClassLoader, поэтому он может видеть только стандартные вещи Android). Я проведу немного больше исследований и посмотрю, смогу ли я что-нибудь придумать. Интересная проблема ...
Является ли исключение точно таким же? Там же, с той же ошибкой? Пожалуйста, опубликуйте исключение снова.
Upvote дляgetClassLoader(), Это помогло мне решитьBadParcelableException изменив это:parcel.readSparseArray(null); к этому:parcel.readSparseArray(MyClass.class.getClassLoader());
Попробуйте это: установить загрузчик классов вhandleMessage() в вашем удаленном сервисе вот так:Bundle bundle = msg.getData(); bundle.setClassLoader(Event.class.getClassLoader()); Event event = (Event) bundle.get(Event.BUNDLE_KEY);

Похожие вопросы