Reputation: 12339
Scenario: I have a Controller
(normal Java class) that must be able to pilot several Slave
s.
A Slave
's nature can differ, so that it can either be:
Service
, let's call it a ServiceSlave
: the lifecycle of this object usually differs from the application's components (say, it does not depend on the current activity)ObjectSlave
: the lifecycle of this object is somewhat bound to the scope in which it is created (say, the current activity)What these two types of Slave
s have in common, is that they can reside in different processes.
Because of this last "requirement", I immediately turned my attention to AIDL
/Messenger
as the form of communication between a Controller
and a Slave
, since it provides IPC.
However, it seems that AIDL
(and in turn Messenger
, since it should be based on AIDL as well) has only been defined if you are to work with a Service
. That is, there is no way for me to implement an AIDL
-based interface without an IBinder
object, which usually is provided in the onServiceConnected
method.
FIRST QUESTION: can AIDL
really be used only when dealing with a Service
? If it is, why so?
Now, consider my scenario. I would like, as any other good developer would, to write a single, elegant interface that allows the Controller
to pilot every Slave
, regardless of their nature. The only solution that came to my mind so far involves using Intent
s and BroadcastReceiver
s, all conveniently wrapped in dedicated Java classes.
SECOND QUESTION: is this the only viable way? Am I overseeing something?
EDIT
I guess I should've given more details on what the Controller
element actually does. It is a component that is loosely coupled with several UI widgets, who subscribe to it. It has been designed (willingly) so that it doesn't need a reference to a Context
. So it doesn't need or use UI widgets directly, but in turn those widgets depend on the Controller
.
Upvotes: 5
Views: 1337
Reputation: 12339
Turns out AIDL
and Binder
are not tied to Service
s.
While it is true that a IBinder
reference is provided only when binding to a Service
, the framework offers the Binder
class, which already implements the IBinder
interface.
Moreover, a Binder
instance works transparently across processes and it is not required to live in a Service
context.
[still elaborating, will provide a scheme on how the structure can be implemented by directly using a Binder instance]
Upvotes: 2
Reputation: 15775
This is a good, but not a simple question to answer. Like most things, there are multiple approaches to take to solve this type of problem. The first thing to examine is whether or not your Controller
needs or uses a UI component. If not, then you'll need to encapsulate it in a Service
. Activity
lifecycle is such that it will only be running when it is the current thing on screen. As soon as the user presses HOME or BACK it is either stopped or destroyed, respectively. Starting another app via notification or from within your app will have an effect similar to pressing HOME: your Activity
will be paused.
So, assuming you don't need/want UI for your Controller
, you have numerous things at your disposal:
Intent
s to take some action. The Service
could then fire back broadcasts or start a specific "slave" Activity
. If interested in this, explore the use of the IntentService
to better manage the threading and prevent ANR of your app.Intent
and have your slave send a Messenger
object it has created as an extra within the Intent
. At that point the Service
can send messages to the Messenger
, which is owned by the slave Activity
and will be delivered to a specific Handler
.You do not need a custom AIDL exposed interface for options 2 and 3. You are correct in that you must define an AIDL interface if you are going to use a bound service and your Service.onBind()
method must return an instance of your binder interface stub implementation.
All of that being said, you could use any of the 3 approaches to meet your goal of working with slave classes which reside in either Activity
or Service
instances. The advantage of using the AIDL or Messenger
approaches is a reduction in context switching (more efficient) since you're not sending Intent
objects. Each time you send an Intent
, the sender contacts the ActivityManagerService
running in a system process to resolve where the Intent
is to be delivered. With AIDL and Messenger
, only the initial bindService()
or startService()
calls reach out to the ActivityManagerService
. After that point the communication is performed using direct binders between the two processes.
Upvotes: 4