Reputation: 309
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
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
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
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
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
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