Using Resultreceiver in Android

Using ResultReceiver in Android

  1. You need to make custom resultreceiver class extended from
    ResultReceiver

  2. then implements the resultreceiver interface in your activity

  3. Pass custom resultreceiver object to intentService and in
    intentservice just fetch the receiver object and call
    receiver.send() function to send anything to the calling activity in
    Bundle object.

    here is customResultReceiver class :

     public class MyResultReceiver extends ResultReceiver {

    private Receiver mReceiver;

    public MyResultReceiver(Handler handler) {
    super(handler);
    // TODO Auto-generated constructor stub
    }

    public interface Receiver {
    public void onReceiveResult(int resultCode, Bundle resultData);

    }

    public void setReceiver(Receiver receiver) {
    mReceiver = receiver;
    }

    @Override
    protected void onReceiveResult(int resultCode, Bundle resultData) {

    if (mReceiver != null) {
    mReceiver.onReceiveResult(resultCode, resultData);
    }
    }

    }

implements the Myresultreceiver.receiver interface in you activity, create a class variable

Public MyResultReceiver mReceiver;

initialize this variable in onCreate:

mReceiver = new MyResultReceiver(new Handler());

mReceiver.setReceiver(this);

Pass this mReceiver to the intentService via:

intent.putExtra("receiverTag", mReceiver);

and fetch in IntentService like:

ResultReceiver rec = intent.getParcelableExtra("receiverTag");

and send anything to activity using rec as:

Bundle b=new Bundle();
rec.send(0, b);

this will be received in onReceiveResult of the activity. You can view complete code at:IntentService: Providing data back to Activity

Edit: You should call setReceiver(this) in onResume and setReceiver(null) in onPause() to avoid leaks.

ResultReceiver from Service to Activity

for simplicity use a local broadcast manager, and register and unregister it in your activity onResume , onPause lifecycles

How does the Android ResultReceiver callback work if it is passed through a Bundle as Parcelable?

ResultReciver implements Parcelable so it can be passed in an intent.

For the startservice it's easier just to load the intent used to start the service with data just like an intent sent to an activity then in the service process the intent data in onStartComand();

If you want to send messages back in forth to a service you should bind to the service startboundservice and in the service return a handler in onBind() to the activity.

This is where the magic of ResultReceiver works. It's just a message that has prepopulated handler so it can be serialized and passed back.

If you just want to get a reply from some fragment class that you create on the fly or something out of the norm actually serialize a callback you can pass in a message populated with the handler that will process the message.

Below I create a handler then create a message with the handler. Then I start a fragment that does something obscure and finally returns the message. So ineffect the message is just a copy but it is actually a callback that is passed in a bundle.

This is new code so I don't know how stable it is...

public void get_UserEmail(final MyGooglePlayCallback userEmailCallback) {

//handle message gets called when the fragment calls msg.sendToTarget()
//
class JX implements Handler.Callback {
@Override
public boolean handleMessage(Message msg) {
Bundle b = msg.getData();
String s = "";
if (b != null) {
s = b.getString("email");
}
msg.recycle();
userEmailCallback.onComplete(s);

return true;
}
}
JX jx = new JX();

Handler h = new Handler(jx);

final Message msg = Message.obtain(h);

MyGooglePlayCallback cb;

// start the account picker to get the email
String[] accountTypes = new String[]{"com.google"};
Intent intentx = AccountPicker.newChooseAccountIntent(null, null,
accountTypes, false, null, null, null, null);

MyFragmentActivityForResult2 f = MyFragmentActivityForResult2.newInstance(
intentx, REQUEST_CODE_PICK_ACCOUNT, msg);

FragmentTransaction fragmentTransaction = fragManager
.beginTransaction();
fragmentTransaction.add(f, "xx" + REQUEST_CODE_PICK_ACCOUNT);
fragmentTransaction.commit();
}

public static class MyFragmentActivityForResult2 extends Fragment {

private Message msg;
private int requestCode;
private Intent intent;

static MyFragmentActivityForResult2 newInstance(Intent intent, int requestCode,
Message message) {

MyFragmentActivityForResult2 f = new MyFragmentActivityForResult2();
Bundle args = new Bundle();
args.putInt("requestCode", requestCode);
args.putParcelable("message", message);
args.putParcelable("intent", intent);
f.setArguments(args);
return f;
}

MyFragmentActivityForResult2() {
}

@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
Bundle b = this.getArguments();
requestCode = b.getInt("requestCode");
msg = b.getParcelable("message");
intent = b.getParcelable("intent");
startActivityForResult(intent, requestCode);
}

@Override
public void onActivityResult(int requestCode, int resultCode,
Intent data) {

super.onActivityResult(requestCode, resultCode, data);

if (requestCode == this.requestCode) {
String mEmail = "";
if (resultCode == Activity.RESULT_OK) {
mEmail = data
.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
}
Bundle b = new Bundle();
b.putString("email", mEmail);
msg.setData(b);
msg.arg1 = requestCode;
msg.arg2 = resultCode;
msg.sendToTarget();
}

fragManager.beginTransaction().remove(this).commit();
}
}

How can I use ResultReceiver in InputMethodManager#hideSoftInputFromWindow

ResultReceiver is not called if hideSoftInputFromWindow returns false.
You can check this value:

boolean hide = inputMethodManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0, new ResultReceiver(null) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
keyboardClosed();
}
});
if (!hide) {
// already hidden
keyboardClosed();
}

Android Service extends ResultReceiver for IntentService, how to implement CREATOR?

your current architecture is too complex imho: you could easily do that in one Service but it is up to you, when it comes to your problem: you don't need to create any CREATOR as what you got is a lint warning, just add SuppressLint annotation like this:

@SuppressLint("ParcelCreator")
public class MyResultReceiver extends ResultReceiver {

Android ResultReceiver across packages

Yes, your idea is possible. The ClassNotFoundException exception is thrown because you are trying to unparcel a class that was created in a different process by a different ClassLoader.

ResultReceiver class implements Parcelable interface which is suitable for inter-process calls (IPC), however to read your object in the service you need to use the same ClassLoader, that was used for object creation in the client application (i.e. in the activity). To get that ClassLoader on the service side, call createPackageContext method passing client package name and CONTEXT_INCLUDE_CODE|CONTEXT_IGNORE_SECURITY combination of flags. This will return client Context object from which the correct ClassLoader object can be obtained.

Example:

public int onStartCommand(Intent intent, int flags, int startId) {
try {

// assuming SignerClient activity is located in the package "com.example.client.A"
Context context = createPackageContext("com.example.client.A", Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
ClassLoader cl = context.getClassLoader();

Bundle bundle = intent.getExtras();
bundle.setClassLoader(cl);
ResultReceiver rr = bundle.getParcelable("resultreceiver");

//... your interaction with ResultReceiver ...
rr.send(1, null); // will result in a onReceiveResult call in the client activity

} catch (NameNotFoundException e) {
Log.e("MyService", "SignerClient package context was not found", e);
throw new RuntimeException(e);
}
return START_STICKY;
}

I've just used it in my code - works like a charm.

UPDATE
However I suggest to consider using Messenger instead of ResultReceiver. It implements Parcelable interface and does not need to be extended thus the ClassLoader issue isn't possible. And it's also recommended in the official documentation.

UPDATE 2
In case you still prefer to use ResultReceiver take a look at Robert's answer in this thread. It looks cleaner and simpler than hacky context manipulations.



Related Topics



Leave a reply



Submit