What are the Android Components anyways?

Marcelo Benites
6 min readNov 8, 2019

Since Google introduced Android Architecture Components and finally became more opinionated about software architecture, some people started referring to it as modern android development. Although those libraries were important to the Android community, specially for newcomers to the Android world, they also created an abstraction on top of the Android SDK.

I am often surprised for the lack of understanding Android developers have about the Android SDK. When interviewing I am always focused on the basics, not only regarding Android development, but also software engineering practices and software architecture. Libraries will come and go, but the Android SDK will always be there, also when developing a complex application a deep understanding of the Android SDK is necessary to come up with a proper solution.

The Components

So what are the components? The five Android components are: Application, Activity, Broadcast Receiver, Content Provider and Service.

Some developers when asked which are the components also include the Fragment or the View, but all the components share an important characteristic: they are declared in the Android Manifest.

The basic components work as an interface of your application with the Android OS. They communicate what your application wishes to expose to third party applications installed in the device and with the Android OS. So let's go and evaluate each of those components one-by-one.

Intents

The messaging mechanism used so Android components can communicate with each other is called Intent. In the AndroidManifest each Android component (besides the Application) can be associated with an IntentFilter that describes which Intents can be used to start them.

Intents are a powerful mechanism because they were created to allow Android components that live in different applications (processes) to communicate with each other. In order to allow IPC (Inter-process Communication) all data associated with Intents has to be serialised, which can be cumbersome when we are dealing with objects. The Parcelable protocol was created to ease the serialisation of objects and to make communication via Intents for more efficient. Since Intents were designed for IPC, we should avoid using them for communication that happens within the boundaries of our application (process).

Application

When the user taps an icon in the home screen of an Android device, the first component to be created will be the Application one. Actually a process is created with a Dalvik VM or Art VM instance, in case there was no process already created for your application.

The Application object is unique within the process and its onCreate method is called only once during the process lifecycle. Actually Application's onCreate is the first of all other components' creational methods to be called*.

The Application's onCreate is the starting point of an Android application and that Application object is a good place to reference other objects that should live during the entire lifecycle of the process.

In case you are familiar with Dagger framework, at least one DaggerComponent is referenced by the Application instance. This DaggerComponent is the one that will manage the Singleton objects that should be unique during the lifecycle of the Application. Other DaggerComponents that should live throughout multiple Activities are also indirectly referenced by the Application. Not only Dagger but any other Dependency Injection framework will use the Application to enable these capabilities.

*ContentProviders are an exception to this rule, but they are used for edge case scenarios as we are going to see in the following sections.

Activity

An Activity is a door we make available to access you application's GUI. You can have many doors, or just one door. The Android OS and other applications are the ones responsible for opening these doors via Intents. For example via a deep link from a Browser, a Google Assistant action, or any other Intent that matches the Intent Filter of your Activity.

The main Activity is the one with Main action and Launcher category in its Intent Filter. That's the door the launcher application uses to enter your application.

So the right motivation one should have to declare a new Activity in the Android Manifest is to create an external door. If your application requires a single door to fulfil its purpose, then using single Activity together with Fragments or Views for internal navigation is the best option for you.

Using multiple Activities for internal navigation is a waste of memory, since the View Hierarchy associated with an Activity is kept in memory while it is in the Back Stack. Fragments are more efficient for internal navigation because their View Hierarchy is destroyed when they are moved to the back stack by the Fragment Manager. That's why Fragments have the onCreateView and the onDestroyView callbacks while Activities don't.

Many developers believe the Android OS "kills" Activities that are in the back stack. That is not true. The Android OS kills processes only. If you have too many Activities in the back stack you will eventually reach the maximum amount of memory reserved to your process. That will end-up causing a OutOfMemoryError.

Broadcast Receiver

The Android OS or other applications can broadcast messages so your application is aware something has changed (e.g. batter level). When a message is broadcasted we may wish to handle it in background or foreground.

When a message needs to be handled in background the Broadcast Receiver works as an optimisation. It is an attempt to avoid starting a Service when it is not necessary. Communication with Broadcast Receivers is done via Intents, just like a Service, so basically we have an Intent Filter which states which Intents that BroadcastReceiver is interested in, but we could theoretically use the same Intent Filter for a Service.

Everything would work, but sometimes we need more logic in order to be sure it is worth to fire a Service or not. Or we just don’t want to start a Service at all, the logic related to the Intent can be processed within the onReceive method of the Broadcast Receiver.

According to Android documentation a the onReceive method should run for around 10 seconds max, so use onReceive for fast calculations based on the received Intent or to decide whether a Service should be started to deal with the Intent.

When a message needs to be handled in Foreground a Broadcast Receiver should be registered dynamically in an Activity or Fragment, instead of in the Android Manifest. That can lead developers to use them for internal communication within the application. There are other options to deal with internal communication, like an Event Bus or a Reactive approach. These options don't require Intents and can be tested independently of the Android SDK, therefore we should favour them.

Service

A Service is a way to communicate the Android OS that your application is doing background work. The Android OS has a priority associated with each application process. Having a running Service associated with your application increases that priority, therefore it makes it less likely for the Android OS to kill your process. If you want an even higher priority you can use a Foreground Service, which requires a Notification to be displayed to the user. The highest priority possible is when your application is in foreground.

When another application tries to bind or start a Service that your application exposes remember that your Application's onCreate method will be called first. If your application process is not running, it will be started and Application's onCreate will be called, only then the Service's onBind or onStartCommand will be called. If your application was already running you are sure OnCreate was already called before.

Many developers focus on starting threads in the Service's onCreate, or onStartCommand, but there is no need to do that. The work that should be performed in the background can be managed by an object that is associated with the Application lifecycle, since we know Application's onCreate is called first. This object just needs to fire a Service when the work starts and kill the Service when the work ends to make sure the Android OS is aware and increases the priority of the applicaiton.

Content Provider

Most applications don't need a Content Provider. The main idea of the Content Provider is to expose data to other applications. It is an overkill to use a Content Provider to access data that is private to your application, instead access the data directly via HTTP, SharedPreferences, the File System or a SQLite Database.

A classic Content Provider usage is in the Contacts application that use it to expose Contact information to external applications.

Internal x External

All the aforementioned components were created to help your application to communicate with the external world: other applications and the Android OS. Android components communicate via Intents that under the hood use Inter Process Communication and Data Serialisation in order to allow components living in different processes (applications) to seamlessly communicate with each other.

For internal communication, internal navigation and internal logic the best is to use more efficient strategies like Fragments, Views, Event Buses and so on. These are decisions that are related to the architecture of your application, while the Android components are related to the Android OS architecture.

--

--

Marcelo Benites

Software engineer passionate about clean code and good beer.