cmg_george
cmg_george

Reputation: 309

Send Object from Service to Activity (Can't marshal non-Parcelable)

I'm trying to send data from my activity to a service and receive some information back, but i'm getting:

java.lang.RuntimeException: Can't marshal non-Parcelable objects across processes.

The code from activity looks like this:

Message msg = Message.obtain(null, 1);
    msg.obj=1;
    msg.replyTo=new Messenger(new PlanRequestIncomingHandler());
    try {
        msgService.send(msg);
    } catch (RemoteException e) {
        Log.i(tag, "Can not send msg to service");
        e.printStackTrace();
    }

When I set msg.obj = something I get java.lang.RuntimeException, can somebody help me?

Upvotes: 13

Views: 10930

Answers (5)

Ahmed Adel Ismail
Ahmed Adel Ismail

Reputation: 2184

I have implemented Actor Model (like Akka) for Android, since Akka requires Java 8, i made my own implementation for it for Android, using RxJava2 , it was very easy to implement ... And once it is there, you can send messages holding any object to any receiver (Activity, Fragment, Service, Pojo, etc.) without worrying about threads or serialization

It is hard to explain my own implementation in details if you dont know what is Actor Model, but if you do, you can make an interface named "Actor" with one method

void onMessageReceived(Message message);

And you can implement this interface by any Actor you have, and to register any Actor, you can create an ActorSystem class that has methods :

static void register(Actor actor, PublishSubject<Message>  mailbox); 
static void unregister(Actor actor);
static void send(Message message, Class<? extends Actor> ... actors);

And when you register your Actor (Activity or Service), you decide what is your thread / scheduler to receive your messages on, through :

PublishSubject.observeOn(Schedulers.trampoline());

And you register your Actor in onCreate() and unRegister in onDestroy()

Or if you want a library for that (but i did not test it), you can take a look at this :

https://github.com/actorapp/droidkit-actors

Upvotes: 0

superman
superman

Reputation: 1

You must use the Bundle to pass the conventional type data, otherwise it will be wrong:

Java.lang.RuntimeException: Can't non-Parcelable objects across marshal processes.

Because the Binder transaction data is called Parcel, the Parcelable interface must be implemented, otherwise it is not possible to communicate between the two applications. The reason why Bundle is passed because the class implements the Parcelable interface. Of course, if you want to pass the class must also implement the interface.

you can write like down:

Message msg = Message.obtain(null, 1);
msg.getData().putInt("key",1);
msg.replyTo=new Messenger(new PlanRequestIncomingHandler());
try {
    msgService.send(msg);
} catch (RemoteException e) {
    Log.i(tag, "Can not send msg to service");
    e.printStackTrace();
}

sorry,my english is very bad

Upvotes: 0

Mohan
Mohan

Reputation: 5105

You can pass Parcelable type objects via Messenger. Or else if you want to pass primitive data types use Bundle wrapper as below.

In Service End:

//Create a bundle object and put your data in it
Bundle bundle = new Bundle();
bundle.putInt("key", 1);

Message msg = Message.obtain(null, 123);
msg.obj = bundle;
msg.replyTo = new Messenger(new PlanRequestIncomingHandler());
try {
    msgService.send(msg);
} catch (RemoteException e) {
    Log.i(tag, "Can't send msg to service");
    e.printStackTrace();
}

In Activity End:

switch(msg.what) {
    case 123:
        if(msg.obj != null) {
            Bundle bundle = (Bundle) msg.obj;
            System.out.println("Got integer "+ bundle.getInt("key"));
        }
    break;
}

cheers :-)

Upvotes: 17

frostymarvelous
frostymarvelous

Reputation: 2805

Old question, but I am answering so it might help someone in the future.

If you are using actual objects, then by all means, please implement Parcelable Android: How to implement Parcelable to my objects?

However, as the OP stated that he tried using Primitives and it did not work, this is what to do.

The problem lies here msg.obj=1; This expects an actual object that implements Parcelable

Use msg.arg1 = 1;

you can then retrieve the argument on the service side using msg.arg1

For simplicity I use (straight from my code)

Message msg = Message.obtain(null, PlayerService.MSG_ACTION_SEEK, i, -1);

The -1 is just a holder for me.

Hope this helps.

Edit: Be careful with

Message msg = Message.obtain(null, PlayerService.MSG_ACTION_SEEK, i);

This signature is equivalent to the OP's first attempt and expects a Parcelable and is what actually tripped me and got me searching in the first place. It won't throw an error until runtime.

Upvotes: 6

serkanozel
serkanozel

Reputation: 2927

Other than primitive data, the objects you're juggling between Activities and Services need to implement Parcelable and preferably Serializable.

I hope this helps,

Best

-serkan

Upvotes: 0

Related Questions