In earlier posts we discussed:
- Android application architecture background
- Architectural patterns implemented by Android application architecture
- Main parts an Android application consists of
Today we are going to discuss various mechanisms through which parts of an Android application collaborate. For lack of better term we’ll call all those mechanisms together as “communication layer” (to my knowledge, Android documentation does not offer any term for this).
As we mentioned earlier, Android application framework implements several communication patterns within its communication layer:
- Message passing which involves Intent class (this involves also late binding)
- Publish/subscribe or pub/sub which also involves Intent class and BroadcastReceiver class
- Late binding and method calls that are used for accessing ContentProviders and local (in-process) Services
- Late binding and Inter-process Procedure Communication (IPC) for invoking remote (AIDL)Services
This is probably the first communication mechanism which a developer encounters while learning Android application development. It is used to start an Activity or a Service. It is implemented via three methods on Context class (which we discussed in one of earlier posts) and one method on Activity class:
- startActivity() of Context class to launch an Activity.
- startActivityForResult() of Activity class to launch an Activity
- startService() or bindService()of Context class to start a Service if needed and to communicate with it (there are slight differences between those two methods; look at the javadocs for more details)
In both cases Intent class plays a role of a message passed.
How does Android know which Activity or Service should receive the message? There are two ways how this is done:
- Intent may specify a name of the target component explicitly. Such Intents are called “explicitIntents” and they specify a target component via setComponent() or setClass() methods of Intent class. This type of Intent-based communication mechanism does not implement late binding pattern while all others do implement it
- Target component is defined by a rather fancy resolution mechanism based on Intent filters.
Please note, in case of message passing communication mechanism the message (an instance of Intent class) is delivered to only one component or not delivered at all.
Publish/subscribe communication mechanism involves the same Intent class as a message and the same intent filters as a resolution mechanism defining target components, but it works quite differently. Intents used for publish/subscribe communication are called “broadcast Intents”. Those broadcast Intents can be delivered to BroadcastReceiversonly. Since BroadcastReceiver is a class and Activity and Service are classes as well, neither Activity nor Service can receive the broadcast Intent (Java prohibits multiple inheritance).
Also, unlike Intent used for message passing, a single broadcast Intent can be delivered to many target components.
In fact, Android implements 2 different publish/subscribe mechanisms each o which has two versions (regular one and sticky one):
- Normal broadcast which is implemented bysendBroadcast() and sendStickyBroadcast() methods of Context class.
- Ordered broadcast which is implemented bysendOrderedBroadcast()and sendStickyOrderedBroadcast()methods of Context class
You are still not confused, right?
Normal broadcast mechanism delivers the Intent to all eligible BrodcastReceivers asynchronously and they act on it independently, i.e. one BrodcastReceiver can’t affect either how another BrodcastReceiver is reacting on the Intent or whether the Intent is delivered to another BroadcastReceiver. It is a regular pub/sub pattern.
Ordered broadcast mechanism delivers the Intent to eligible BrodcastReceives in a sequential manner, i.e.toone at a time. Due to this each BrodcastReceiver can potentially:
- Use results produced by previous BroadcastReceivers that worked on the same Intent
- If needed, abort further processing of the Intent
By executing ordered broadcast, a component which initiated it gets opportunity to receive the result of processing the Intent by all BroadcastReceivers in the chain.
Ordered broadcast actually is an implementation of chain-of-responsibility design pattern.
Sticky broadcasts are versions of the corresponding regular broadcasts. The difference is the Intent is available until it is explicitly removed by removeStickyBroadcast() method of Context class. Please note, this type of broadcast should be used with great caution since not removing the sticky Intents will result in a memory leak.
Conclusion on Intent-based communication mechanisms
All communication mechanisms described so far make use of Intent class as a message. Please note, that majority of corresponding methods are implemented by Context class so they can be theoretically used by all subclasses on the Context class.
By this point one may start thinking that all Android application communication mechanisms are using Intent class. Not at all.
Late binding of ContentProvider
ContentProvider class is essentially a wrapper around SQLite database in most cases although theoretically it can use other persistence mechanisms to store/retrieve data. You can read more about the class and its usage here.
There are many ways how Android code can use ContentProviders. Some of them include getting an object which acts as a proxy to the ContentProvider (normally it is an instance of a subclass of ContentProviderClient, which implements proxy design pattern). Some of them return an instance of Cursor class which allows iterating through data set returned by ContentProvider. In all cases the concrete ContentProvider which is going to be used is identified through URI (see details here).
Overall, it is a typical late binding pattern.
Late binding and Inter-process Procedure Communication (IPC) of Service
If you think it’s all communication mechanisms, you are mistaken.
Apart of ContentProvider class there is Service class which architecturally plays the same role of Model in MVVM architecture pattern. We have discussed the hypothetical reasons why Android has two different classes to fulfill the same role in the previous post here.
There are two types of Service and each requires a separate communication mechanism:
- Local Service which runs within the same process where it is invoked. Architecturally it is similar to ContentProvider apart that it has its own lifecycle and it is not necessarily backed by DB. A version of late binidng is used to access the local services
- Remote Service which runs within another process from where it is invoked. Such type of service is accessed through a sort of IPC call implemented using AIDL (Android Interface Definition Language)
It is worth mentioning that the same Service may be used as both Local and Remote; the difference is in where the component which invokes the Service is located (within the same process or in another process).