2

I read some similar questions (for example at this link), but the problem I'm asking is a bit different. In fact, in my case the service is started manually by the startService method, then as a consequence it can not be started using the bindService method.

  1. Suppose we have a package that contains the MainService service and MainServiceActivity activity. In the file "AndroidManifest.xml" this activity is declared with action MAIN and category LAUNCHER. This activity is used to configure the service via the SharedPreferences and start the service by invoking startService method. In other words, typically the user launches the MainServiceActivity and configures/starts the MainService.
  2. Now consider another activity (Let's call it SecondActivity) that is part of another package. Depending on the configuration, the service starts this activity using the startActivity method, so this other activity is running on a separate process than the MainService. As soon as the activity is running, it should inform the service.
  3. At this point, a communication request/reply begins between the MainService and the SecondActivity: the service sends a request and the activity sends a reply.

The communication via messaging might fit, but the MainService is started through startService method, so the bindService method can not be invoked by activities that want to bind to the service.

Then I had an idea that makes use of an additional service (Let's call it UtilityService), which is part of the same package of MainService: the UtilityService could be started using the bindService method. As a consequence:

  • as soon as the MainService is running, it might perform the bind to the UtilityService;
  • when the MainService launches an external activity (for example the above SecondActivity), this activity bind to the UtilityService.

In this way, both the MainService and the SecondActivity are connected to the UtilityService, where the latter acts as an intermediary for communication.

Are there alternatives to this idea?

Community
  • 1
  • 1
enzom83
  • 8,080
  • 10
  • 68
  • 114

2 Answers2

4

In fact, in my case the service is started manually by the startService method, then as a consequence it can not be started using the bindService method.

You can both bind and start a service, if you wish. It's a bit unusual, but it can be done.

Are there alternatives to this idea?

Binding has nothing in particular to do with services being able to communicate with activities. Using some sort of callback or listener object via binding is a possibility, but it is far from the only one.

You can:

  • Have the service send a broadcast Intent, to be picked up by the activity

  • Have the activity send a PendingIntent (e.g., via createPendingResult()) to the service in an Intent extra on the command sent via startService(), to be used by the service to send information back to the activity (or wherever the activity wants it to go, such as a broadcast)

  • Have the activity pass a Messenger tied to its Handler to the service in an Intent extra on the command sent via startService(), to be used by the service to send information back to the activity

All of those work perfectly well between processes, as well as within a process.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • _You can both bind and start a service, if you wish. It's a bit unusual, but it can be done._ Ok, it works! But, why is it unusual? – enzom83 Apr 28 '12 at 16:58
  • 1
    @enzom83: It is unusual because virtually nobody does it. Usually the command pattern (`startService()`) *or* the binding pattern (`bindService()`) is used. – CommonsWare Apr 28 '12 at 17:04
  • Using a broadcast intent, can you decide who should receive it? I read about `setPackage` method in order to safely restrict the broadcast ([here](http://developer.android.com/reference/android/content/BroadcastReceiver.html#Security), the fourth bullet point), but I'm working on Android 2.3. However I also read about the [`setComponent` method](http://developer.android.com/reference/android/content/Intent.html#setComponent%28android.content.ComponentName%29), so I could set a known `BroadcastReceiver` as the destination of a broadcast intent. So would I get a kind of `sendUnicast` method? – enzom83 May 10 '12 at 15:46
  • @enzom83: "I'm working on Android 2.3" -- `setPackage()` was added in API Level 4. "So would I get a kind of sendUnicast method?" -- that only works for manifest-registered receivers, which will not work for your scenario. You are welcome to use `LocalBroadcastManager` from the Android Support package, as I illustrate here: https://github.com/commonsguy/cw-advandroid/tree/master/Broadcast/Local – CommonsWare May 10 '12 at 15:54
  • Ok, `setPackage` was added in API Level 4, but [here](http://developer.android.com/reference/android/content/BroadcastReceiver.html#Security) it says that _"starting with ICE_CREAM_SANDWICH, you can also safely restrict the broadcast to a single application with `Intent.setPackage`"_ However, about that kind of sendUnicast method, why does it will not work for my scenario? I could create a `BroadcastReceiver` (as an inner public class) in the service and another one in the activity and declare these receivers on the manifest of the two application packages... Or am I wrong? – enzom83 May 10 '12 at 17:05
  • 1
    @enzom83: " I could create a BroadcastReceiver (as an inner public class)" -- which will not work. You could register a `static public` inner class in the manifest. Android will then create a brand-new instance of that `BroadcastReceiver` when a broadcast is received, and that `BroadcastReceiver` instance will have no more ability to talk to your activity than does your current service. IOW, `setComponent()` and `registerReceiver()` cannot work together. – CommonsWare May 10 '12 at 17:46
  • Ok, now I understand the reason. Thanks! I just saw that I can not declare an inner class defined in an activity as a receiver, so I should I declare it as static: however, declaring it static, it could not invoke non-static methods of my Activity.... But, just out of curiosity, why can not you register a simple inner class as a receiver? – enzom83 May 10 '12 at 18:10
  • 1
    @enzom83: Because Android needs to create an instance of a manifest-registered `BroadcastReceiver`, and only an instance of the outer class can create an instance of a non-static inner class. – CommonsWare May 10 '12 at 18:16
  • And, what about [this idea](http://stackoverflow.com/a/4854830/364056)? Could it work? – enzom83 May 10 '12 at 19:18
  • @enzom83: Not with `setComponent()`. – CommonsWare May 10 '12 at 19:21
1

You can use Android Interface Definition Language (AIDL).

You can find an easy to use guide here

rui.araujo
  • 9,597
  • 1
  • 18
  • 24
  • AIDL is an option. It is most certainly not the only option. – CommonsWare Apr 27 '12 at 23:01
  • @rui.araujo: I read something about AIDL and I understood that its goal is the same as the messaging, but AIDL should be is more simple compared to the messaging. I looked at the guide you have linked and tomorrow I will read it in more detail. – enzom83 Apr 27 '12 at 23:09
  • @CommonsWare You're right. Using "have to" is silly. Still I like AIDL the most. It just feels clean. ;) – rui.araujo Apr 27 '12 at 23:11
  • Well, I read the guide you have linked and I also tried an example available [here](https://github.com/commonsguy/cw-advandroid/tree/master/AdvServices) (RemoteClient and RemoteService). Now I'm trying to reverse the direction of communication, that is, from the remote service to the client. – enzom83 Apr 28 '12 at 16:34
  • I am interested in this solution u mention in the last comment @enzom83 . Did u make any progress with it? 10q – Ewoks Feb 18 '13 at 15:19
  • 2
    @Ewoks: To establish a bidirectional communication, I defined two AIDL interfaces, `IService` and `IServiceCallback`: the application sends data to the service using the `IService` interface, and the service sends data to the application using the `IServiceCallback` interface. [This page](http://developer.android.com/guide/components/aidl.html) explains how to implement an AIDL interface. – enzom83 Feb 23 '13 at 14:07