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

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?

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 :-)

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.

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

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

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

Related

How do I route GCM messages from a GcmListenerService to their relevant handlers?

The app that I am working on has two services (Pushwoosh and Helpshift) that use GCM for push notifications. I am attempting to implement the functionality shown here, in the Pushwoosh documentation, to allow both systems to function; https://docs.pushwoosh.com/v1.0/docs/gcm-integration-legacy. However my Android knowledge is failing me for how I actually route the bundle recieved to the relevant handlers. The project is dones in Unity but this is very much Android territory.
Here is the GcmListenerService class I have created that is very similar to the example;
import android.os.Bundle;
import android.content.Intent;
import android.util.Log;
import com.google.android.gms.gcm.*;
import android.content.ComponentName;
public class GCMListenerRouterService extends GcmListenerService
{
public GCMListenerRouterService()
{
super();
Log.i("Unity", "GCMListener - Constuctor");
}
private void dispatchMessage(String component, Bundle data)
{
Log.i("Unity", "GCMListener - dispatchMessage: " + (data != null ? data.toString() : "<null>") + " component: " + component);
Intent intent = new Intent();
intent.putExtras(data);
intent.setAction("com.google.android.c2dm.intent.RECEIVE");
intent.setComponent(new ComponentName(getPackageName(), component));
GcmReceiver.startWakefulService(getApplicationContext(), intent);
}
#Override
public void onMessageReceived(String from, Bundle data)
{
Log.i("Unity", "GCMListener - onMessageReceived: " + (data != null ? data.toString() : "<null>") + " from: " + from);
// Base GCM listener service removes this extra before calling onMessageReceived
// Need to set it again to pass intent to another service
//data.putString("from", from);
//if (TextUtils.equals(from, getString(R.string.PUSHWOOSH_PROJECT_ID)))
//{
// dispatchMessage(PushGcmIntentService.class.getName(), data);
//}
//else if (TextUtils.equals(from, getString(R.string.PRIVATE_PROJECT_ID)))
//{
// dispatchMessage(PrivateGCMListenerService.class.getName(), data);
//}
}
}
I am able to confirm that the push notification came from the correct messaging service, and I can determine if a push notifications came from one plugin or another. How do I route these bundle objects to the correct handler? I do not understand the following sample code;
if (TextUtils.equals(from, getString(R.string.PUSHWOOSH_PROJECT_ID)))
{
dispatchMessage(PushGcmIntentService.class.getName(), data);
}
else if (TextUtils.equals(from, getString(R.string.PRIVATE_PROJECT_ID)))
{
dispatchMessage(PrivateGCMListenerService.class.getName(), data);
}
I appreciate that this is example code but I can't find any functions in the Android documentation with the same signature as dispatchMessage. Do I need to make an intent service for each different type of message that is needed?
I know that for Helpshift I need to call a function with the signature handlePush(Context context, Bundle data) but I'm not sure what the Context object is. For Pushwoosh, i'm not sure what the handler is. While I am talking about two particular services I am assuming that this setup is a standard method for receiving messages and handling them.
Turns out that, for that for GCM, Bundle objects are the raw push details that you need to be handled. No further processing is needed and plugins/frameworks that support GCM should have a function that handles this, e.g. For helpshift that function is in com.helpshift.Core called handlePush(Context context, Bundle data).
Note that GCM is actually deprecated and Firebase Cloud Messenger is the new system going forward. This service has a different way of dealing with multiple push handlers and you should check your plugins for documentation on this.

How can I DetectFaces in Amazon Rekognition AWS with Android Studio?

I have tried so many way but i can't succeed. I haven't found any source code examples for Android(about rekognition)
there's a source code in JAVA in the Developer Guide but i cannot implement that even though I tried TT
I try to detect faces by sending an image file from an external storage(from the emulator)
I don't know what i did wrong(I'm not good at coding)
Here is my code
AmazonRekognitionClient amazonRekognitionClient;
Image getAmazonRekognitionImage;
DetectFacesRequest detectFaceRequest;
DetectFacesResult detectFaceResult;
File file = new File(Environment.getExternalStorageDirectory(),"sungyeol.jpg.jpg");
public void test_00(View view) {
ByteBuffer imageBytes;
try{
InputStream inputStream = new FileInputStream(file.getAbsolutePath().toString());
imageBytes = ByteBuffer.wrap(IOUtils.toByteArray(inputStream));
Log.e("InputStream: ",""+inputStream);
Log.e("imageBytes: ","");
getAmazonRekognitionImage.withBytes(imageBytes);
// Initialize the Amazon Cognito credentials provider
CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
getApplicationContext(),
"us-east-2:.......", // Identity Pool ID
Regions.US_EAST_2 // Region
);
//I want "ALL" attributes
amazonRekognitionClient = new AmazonRekognitionClient(credentialsProvider);
detectFaceRequest = new DetectFacesRequest()
.withAttributes(Attribute.ALL.toString())
.withImage(getAmazonRekognitionImage);
detectFaceResult = amazonRekognitionClient.detectFaces(detectFaceRequest);
detectFaceResult.getFaceDetails();
}
catch(Exception ex){
Log.e("Error on something:","Message:"+ex.getMessage());
}
and here is my errors
02-04 09:30:07.268 29405-29405/? E/InputStream:: java.io.FileInputStream#a9b23e7
02-04 09:30:07.271 29405-29405/? E/Error on something:: Message:Attempt to invoke virtual method 'com.amazonaws.services.rekognition.model.Image com.amazonaws.services.rekognition.model.Image.withBytes(java.nio.ByteBuffer)' on a null object reference
what is a null object reference?
i try to change the file path but he said no such file ... and when I change to this path, there's errors above.
by the way I've already asked a user for a permission to access a folder from Emulator in Android
please help me
PS. sorry for my bad English
Thank you in advance.
Now I am ok with the issues. I have been through many many things <3 <3 <3.
Thank you
I'm Thai and I had to try harder to find the solutions because there's lack of information in the particular language. Here are my solutions.
My solutions are:
0.There is an endpoint for setting for the Rekognition-->
http://docs.aws.amazon.com/general/latest/gr/rande.html#rekognition_region
1.On a "null object reference issue" I found that I have to create a new object first such as "Image image = new Image();" <-- The "new" command creates an object instance in that class
2.After the above error, there are more errors (Errors on NetworkOnMainThreadException), so I tried everything until I found this page -->
https://docs.aws.amazon.com/cognito/latest/developerguide/getting-credentials.html the page said that ...
Consequently, I looked up for more information about the AsyncTask and after that I created an AsyncTask class and then I move all my code about the initialize, the request, the response to the AsyncTask class. ตอนรันตอนท้ายๆน้ำตาจิไหล my code worked... TT and by the conclusion the sungyeol.jpg.jpg file worked
for example
private void testTask(){
.... all code in the main thread particularly on the requests and responses
from the services
//print the response or the result
//Log.e() makes the message in the android monitor red like an error
Log.e("Response:", [responseparameter.toString()]);
}
//create the inherited class from the AsyncTask Class
//(you can create within your activity class)
class AsyncTaskRunner extends AsyncTask<String,String,String>{
#Override
public String doInBackground(String ... input){
testTask(); // call the testTask() method that i have created
return null; // this override method must return String
}
}
//I've created a button for running the task
public void buttonTask(View view){
AsyncTaskRunner runner = new AsyncTaskRunner();
runner.execute();
}
for more information about the AsyncTask:
https://developer.android.com/training/basics/network-ops/connecting.html#AsyncTask
http://www.compiletimeerror.com/2013/01/why-and-how-to-use-asynctask.html#.WJdkqVOLTIU
I hope these help :)

Saving sender reference in Actor field

I am novice to Akka and I will be very glad is someone with Akka experience could help me. I read following article http://doc.akka.io/docs/akka/2.4.1/java/untyped-actors.html and part with title "Lifecycle Monitoring aka DeathWatch" contains following example:
public class WatchActor extends UntypedActor {
final ActorRef child = this.getContext().actorOf(Props.empty(), "child");
{
this.getContext().watch(child); // <-- the only call needed for registration
}
ActorRef lastSender = getContext().system().deadLetters();
#Override
public void onReceive(Object message) {
if (message.equals("kill")) {
getContext().stop(child);
lastSender = getSender();
} else if (message instanceof Terminated) {
final Terminated t = (Terminated) message;
if (t.getActor() == child) {
lastSender.tell("finished", getSelf());
}
} else {
unhandled(message);
}
}
}
For me is not clear why we could save sender ref in actor field lastSender. For example we could have following situation: actor A send kill message to WatchActor, we save in WatchActor lastSender field reference of actor A, then actor B send kill message to WatchActor, we save in WatchActor lastSender field reference of actor B, Watch actor receiver Terminated message from child actor and answer to actor B, but actor A will not receive answer. Is this code incorrect?
What you describe could happen is correct, so the example is not entirely safe and could have unexpected outcome if multiple actors would send the "kill" message to WatchActor. The example in the docs could probably be improved in this regard.
It is annoying but maybe not super relevant to the section of the docs, which essentially describes how an actor will receive Terminated once another actor it watches has been stopped and that it happens asynchronously.
Please file a ticket here if you think it is important enough: https://github.com/akka/akka/issues

Communicate from Service to Activity via bound service

I've already bound an activity to my service following this tutorial.
http://developer.android.com/guide/components/bound-services.html
I'm able to call service functions, but what if I want to for example, change some of my textviews or disable some of the toggle buttons because of work done on the service (and from the service). Would there be an easy to way to do this?
You can use messages to send information between activities and services. This is an easy way to send simple data, but may not be the best option if you need to send data very frequently, or send complicated data. This is an example of some code I have in one of my apps with a service and an activity which communicate:
Code in the activity:
//this is where you set what you want to happen
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
//this switch reads the information in the message (usually just
//an integer) and will do something depending on which integer is sent
case 1: do_something();
case 2: do_something_2(); //etc.
default:
super.handleMessage(msg);
}
}
}
final Messenger myMessenger = new Messenger(new IncomingHandler());
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
myService = new Messenger(service);
myCallbackText = (TextView)findViewById(R.id.tv01); //This is a text view which will display status information as needed
myCallbackText.setText("Attached.");
try {
Message msg = Message.obtain(null,
1);
msg.replyTo = mMessenger; //here we send an instance of our messenger implementation as the replyTo address
mService.send(msg);
msg = Message.obtain(null,
3, this.hashCode(), 0);
mService.send(msg); //send a message with the value "3"
} catch (RemoteException e) {
//nothing you can do if the server isn't active
}
Toast.makeText(Service_testActivity.this, R.string.remote_service_connected,
Toast.LENGTH_SHORT).show();//confirmation that the connection happened successfully
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mService = null;
mCallbackText = (TextView)findViewById(R.id.tv01);//same textview as before
mCallbackText.setText("Disconnected.");
Toast.makeText(Service_testActivity.this, R.string.remote_service_disconnected,
Toast.LENGTH_SHORT).show();
}
};
Code in the service:
In the service, you will want to have code (very similar to the code in the activity) to receive a message and save the msg.replyTo field as a Messenger object. There is an example somewhere which will have you make an object and then use an IncomingHandler like this:
ArrayList<Messenger> mClients = new ArrayList<Messenger>();
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REGISTER_CLIENT:
mClients.add(msg.replyTo);
break;
case MSG_UNREGISTER_CLIENT:
mClients.remove(msg.replyTo);
break;
default:
super.handleMessage(msg);
}
}
}
This can allow your service to keep track of multiple clients at once and send messages to specified clients. To send a message simply use something like this:
mClients.get(1).send(Message.obtain(null, 3, new Random().nextInt(), 0));
//sends a message to the first client saved in the list

Sending ordered broadcast to a specific receiver?

How can I send an orderedBroadcast to a specific receiver? I am broadcasting the ACTION_MEDIA_BUTTON and only want a specific app (Winamp for example) to receive it. I don't want Pandora to steal it. Is there a way to explicitly define who the receiver will be?
void sendBroadcast() {
Intent i = new Intent(Intent.ACTION_MEDIA_BUTTON);
synchronized (this) {
i.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, theKeyEvent));
ctx.sendOrderedBroadcast(i, null);
i.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, theKeyEvent));
ctx.sendOrderedBroadcast(i, null);
}
}
If you know the package of the Winamp application, you can use setPackage to restrict Intent resolution to only a specific package.

Categories

Resources