Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

My app relies on a Service which stays in sync with external hardware in the background. Because the service operates on the main Thread, it does any heavy work asynchronously using an IntentService. Here is a minimalized example of the code to explain the control flow:

public class MyService extends Service {
  private final Handler handler = new Handler();

  void someMethodDoesCallBarAsynchronously(){
    Intent i = new Intent(this, MyIntentService.class);
    i.putAction(ACTION_FOO);
    i.putExtra(EXTRA_RECEIVER, new MyResultReceiver(handler));
    startService(toGetScannerStatus);
  }

  void receivedFooResult(String bar){
    //...
  }

  public class MyResultReceiver extends ResultReceiver{

    public MyResultReceiver(Handler handler){
      super(handler);
    }

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

      switch(resultCode){
        case RESULT_CODE_FOO:
          receivedFooResult(resultData.getString(FOO_RESULT));
        break;
      }
    }
  }
}

public class MyIntentService extends IntentService {

  public MyIntentService(){super("MyIntentService");}

  @Override
  protected void onHandleIntent(Intent intent) {
    switch (intent.getAction()) {
      case ACTION_FOO:
        ResultReceiver receiver = intent.getParcelableExtra(EXTRA_RECEIVER);
        Bundle bundle = new Bundle()
        bundle.putString(FOO_RESULT, foo());
        receiver.send(RESULT_CODE_FOO, b);
      break;
  }
}

Now, after half a year and some updates, Android Studio complains that MyResultReceiver implements Parcelable but does not provide a CREATOR field. Problem one, MyResultReceiver is an inner class, so I have to put it into an own class. I cannot make it static because it must hold a reference to MyService. That is still quite easy:

public class MyService extends Service {
  private final Handler handler = new Handler();

  void someMethodDoesCallBarAsynchronously(){
    Intent i = new Intent(this, MyIntentService.class);
    i.putAction(ACTION_FOO);
    i.putExtra(EXTRA_RECEIVER, new MyResultReceiver(this, handler));
    startService(toGetScannerStatus);
  }

  void receivedFooResult(String bar){
    //...
  }
}

public class MyResultReceiver extends ResultReceiver{
  private final MyService myService;

  public MyResultReceiver(MyService s, Handler handler){
    super(handler);
    this.myService = myService;
  }

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

    switch(resultCode){
      case RESULT_CODE_FOO:
        myService.receivedFooResult(resultData.getString(FOO_RESULT));
      break;
    }
  }
}

Now I can add a public static field. But how to implement CREATOR correctly?

public class MyResultReceiver extends ResultReceiver {

  public static final Parcelable.Creator<MyResultReceiver> CREATOR
    = new Parcelable.Creator<MyResultReceiver>() {
        public MyResultReceiver[] newArray(int size) {
          return new MyResultReceiver[size];
        }
        public MyResultReceiver createFromParcel(Parcel in) {
          // ???
        }
      };

If you want to: Why is this necessary? What will it be used for?

like image 583
Matthias Ronge Avatar asked Nov 24 '15 08:11

Matthias Ronge


People also ask

What can I use instead of IntentService on Android?

Consider using WorkManager or JobIntentService , which uses jobs instead of services when running on Android 8.0 or higher. IntentService is an extension of the Service component class that handles asynchronous requests (expressed as Intent s) on demand. Clients send requests through Context.

What is difference between service and IntentService in Android?

If the task doesn't require any and also not a very long task you can use service. If the Background task is to be performed for a long time we can use the intent service. Service will always run on the main thread.

What happens if multiple intents are passed to a started service?

Multiple requests to start the service result in multiple corresponding calls to the service's onStartCommand(). However, only one request to stop the service (with stopSelf() or stopService()) is required to stop it.


1 Answers

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 {
like image 164
pskink Avatar answered Oct 01 '22 19:10

pskink