4

I'm coding and android app which have 2 process, One is obviously the main process which handle all the UI things and other stuffs and the other process hosts a service that handles network(socket) listening and other things.

To communicate across the two process, I use the Messenger approach, and works great until I need to send custom java objects. This java class implements the Parcelable interface, which allows Messenger to send java object across process boundaries.

Here is an exmple of my java class I want to send.

package com.locator.carlocator.models;

import android.os.Parcel;
import android.os.Parcelable;

public class Phone implements Parcelable {

    public String number;
    public String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }


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

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.number);
        dest.writeString(this.name);
    }

    public Phone() {
    }

    private Phone(Parcel in) {
        this.number = in.readString();
        this.name = in.readString();
    }

    public static final Parcelable.Creator<Phone> CREATOR = new Parcelable.Creator<Phone>() {
        @Override
        public Phone createFromParcel(Parcel source) {
            return new Phone(source);
        }

        @Override
        public Phone[] newArray(int size) {
            return new Phone[size];
        }
    };
}

And this is how I crate the object instance I want to send, this is triggered by a message received and then send to the main process. The next block of code runs on a service which runs on a different process and communicates using Messenger IPC built in API.

Phone phone = new Phone();
phone.setNumber("6000-0006");
phone.setName("Alex Sanchez");

data = new Bundle();
data.setClassLoader(Phone.class.getClassLoader());
data.putParcelable("key-phone", phone);

Message msg = Message.obtain(null, MSG_A_REQUEST);
msg.setData(data);
notifySubscribers(msg);   // this method perform the send message.

how is implemented the sender method?

private void notifySubscribers(Message msg) {
    for(Messenger subscriber : serviceSubscribers) {
        try {
            subscriber.send(msg);
        } catch (RemoteException e) {
            Log.e(TAG, "Subscriber not available");
            e.printStackTrace();
        }
    }
}

And here is part of the stack trace:

00:53:05.382 21542-21542 E/Parcel: Class not found when unmarshalling: com.locator.carlocator.models.Phone
                                     java.lang.ClassNotFoundException: com.locator.carlocator.models.Phone
                                         at java.lang.Class.classForName(Native Method)
                                         at java.lang.Class.forName(Class.java:309)
                                         at java.lang.Class.forName(Class.java:273)
                                         at android.os.Parcel.readParcelableCreator(Parcel.java:2281)
                                         at android.os.Parcel.readParcelable(Parcel.java:2245)
                                         at android.os.Parcel.readValue(Parcel.java:2152)
                                         at android.os.Parcel.readArrayMapInternal(Parcel.java:2485)
                                         at android.os.BaseBundle.unparcel(BaseBundle.java:221)
                                         at android.os.Bundle.getParcelable(Bundle.java:755)
                                         at com.locator.carlocator.MainActivity$IncomingHandler.handleMessage(MainActivity.java:2255)
                                         at android.os.Handler.dispatchMessage(Handler.java:102)
                                         at android.os.Looper.loop(Looper.java:135)
                                         at android.app.ActivityThread.main(ActivityThread.java:5343)
                                         at java.lang.reflect.Method.invoke(Native Method)
                                         at java.lang.reflect.Method.invoke(Method.java:372)
                                         at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:907)
                                         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:702)
                                      Caused by: java.lang.ClassNotFoundException: Didn't find class "com.locator.carlocator.models.Phone" on path: DexPathList[[directory "."],nativeLibraryDirectories=[/vendor/lib, /system/lib]
AXSM
  • 1,142
  • 1
  • 12
  • 27
  • The bytecode of the class must be available in the receiving process. Did you include the class in the build? – Henry Jul 23 '16 at 06:12
  • I think so @henry, since the class is part of the application package, `Phone` is a class I just build for demo purposes, but having the same result, If not, show me the way – AXSM Jul 23 '16 at 14:33
  • @commonsware here is the question itself. – AXSM Jul 23 '16 at 15:06
  • 1
    Need to handle Intent/Bundle http://stackoverflow.com/questions/28589509/android-e-parcel-class-not-found-when-unmarshalling-only-on-samsung-tab3 – VVB Jul 24 '16 at 06:30
  • @VVB I had no idea the class loader used by the bundle has to be set at the final point when unmarshalling. That's the key, set the class loader before `data.getParcelable("key-object")` – AXSM Jul 26 '16 at 22:06

0 Answers0