Let’s post command to other app Handler
In chapter 1, we discussed what is Handler and why is it designed the way it is. The short summary is Handler is not related to UI thread, we use Handler for Thread communication. Any two threads can communicate (pass commands) to each other using this smart mechanism of Handler, Message, and Looper. If you have not read Chapter 1, I recommend reading.
What if I say you can use Handler across apps. Yes, you read right. You can post a message to any other app you want (I said you can post, they will accept is up-to them). More accurately, if two processes want they can use Handler simple interface to communicate with each other.
Note: This chapter requires Android Service knowledge. If you do not know Service, bind Service; come back later.
There are a few ways apps can communicate in Android, e.g BroadcastReceiver, Content Provider, Inter-Process Communication. IPC is a generic term and there are again a few ways to accomplish same.
This chapter is about IPC with Handler. First, let me shed some light on another important topic, Binder. Though Binder itself demands its own Chapter, it is out of scope to discuss in detail.
Binder
All you can say about Binder is: It is the driving force behind Android. It is like the guy/girl who works his/her ass off and no one recognises. Everyone congratulates the presenter, no one knows who really worked hard so much and whose brainchild the product is. Every one praised Steve Jobs, Few cared Wozniak. If you know the true worth of Wozniak, you will appreciate Binder as well. Keep in mind, both Wozniak and Jobs were important in history. Without former, there was no such superior tech product and without the latter, there was no Apple. Same in Android, Binder does the heavy lifting and it is happy in doing what it does best.
Okay, enough of emotional drama! What does it do that I am making it your Hero for the day? In one sentence, it runs Android. If you are a naive developer, it will take 9 months (keep guessing why) for you to understand that an Android app is not one app.
It is few Components packed in one zipped file and they decided to share the memory space. Android system sees your app as these components few of which are available to other components across process boundary (export=true, intent-filter).
Okay don’t leave, I am coming back to Binder. When any two components in Android communicate, say you start any Intent and some app resolves to fulfill your query. Binder is the force behind making it happen. Suppose there is any permission requirement, It is Binder which makes sure right permissions are granted to the caller. Binder is a system service which acts like a chain whenever communication is needed between components. I am not sure I have a feeling You were expecting Thor and I gave you Loki (Again so many hidden powers).
All base set. Let’s see how Handler and Binder are connected!
Service
The mechanism is bindService. When we bind to a service we enter into the realm of Client-Server model. The service you bind to acts as a Server and your service connection acts as Client.
Client calls:bindService(intent, serviceConnection, Service.BIND_AUTO_CREATE);
The connected service has to return IBinder instance.
Service gets the call in:public IBinder onBind(Intent intent)
IBinder is an interface which Binder implements. Binder is a wrapper over System Service which is responsible for component communication. So, when we bind to a service, it returns something which has the capability to communicate across processes.
Where do we get IBinder from? This is a very complicated interface and developers will not implement it in most of the cases. One solution is to extend Binder and return Binder object and receiver receive it in onServiceConnected.
The client gets back:onServiceConnected(ComponentName name, IBinder service)
If you are binding to your service in the same app, you could be doing something like:
public class CustomBinder extends Binder {
public MyService getMyService() {
return MyService.this;
}
}
Here we are just returning a Binder subclass with a new method added which receiver has complete knowledge about and they can cast IBinder to CustomBinder and call getMyService method.
But you can bind a service of any other app. The client does not know the CustomBinder and can not cast it.
Post Office Analogy
Handler is like a post office section where all posts of one particular area will be dropped so it can be processed with ease and speed. It is just the address of area inside the post office. But the outer world only knows post office, you do not go to post office and goto section B12 because you know the post you are about to send will be sorted there. You interact with a facade. Similarly Binder is the facade for the outer world which knows the internal address.
Handler has a method called
final IMessenger getIMessenger()
This gives outer world address which you can share with others, they will deliver to this address and Binder knows the message is intended for which Handler.
The secret sauce is Messenger
To make things easy, Android offers another class Messenger. This converts Handler to Binder and it offers a capability to send message to Binder. The beauty of this class is it is Parcel-able. In reality, transferring just some bits containing the addresses of both parties.
Both parties connect to the address and whatever they send, routes via Binder. The real hero is still Binder, working all the time silently. (Its manager says you meet expectation. Next time, work hard to exceed and you will get a bonus, we need a different manager)
To sum up, Sender will send Binder from some Handler. The trick is to use Messenger.
return new Messenger(handler).getBinder();
The receiver will create Messenger using same Binder
public void onServiceConnected(ComponentName name, IBinder binder) {
messenger = new Messenger(binder);
}
Now both the client and the server are communicating via Binder. The client can send message to Other process handler with:
messenger.send(message);
And thats how one process can communicate with other. Is something missing? A process can send a message to process B using above mentioned way. But how B will respond back to A?
Again, secret sauce Messenger.
Each message has a dedicated field replyTo which is also a Messenger. In simple words, address of another Handler.
In Client Process you can have one:replyMessenger = new Messenger(handler);
and before sending message, you can attach this to message.
// Create Message with data
message.replyTo = replyMessenger;
messenger.send(message);
Server will receive the message in handleMessage of their Handler.
public void handleMessage(Message msg)
and they can respond via replyTo Messenger
public void handleMessage(Message msg) {
// process message
// create a new Message for client
msg.replyTo.send(reply)
}
In summary, Binder is the force in Android which ensures two components can communicate. Binder is a wrapper above System service. Handler has an address like a post office section and it registers its section with Binder using Messenger. Messenger is a Parcel-able object which is like bits of addresses. Processes communicate via system service Binder, which is Post office. They send messages via Messenger which has internal section address and Binder ensures the delivery.