Many people entering the Android Development often come across the “Android Context”, but eventually they end up just “passing a context” whenever needed via the Application or the Activity, and be done with it, without ever looking any further into it.

This can lead to a lack of fundamental understanding when it comes to how your app really works, and can even lead to memory leaks and app crashes.

Additionally, this lack of understanding widens by not realizing the close relationship between the Manifest and the Context in regards to the Android System.

In this article, I will attempt to provide a coherent approach to the Manifest, the Context, and the underlying architecture, and not a technical one, as “understanding should precede learning”.

what is the Android Context?

A handle to the Android System.

what is the App Manifest?

The place to declare the app package information, the permissions, and the components of the app to the Android System.

Deja Vu?

Did you notice that in both terms I used the phrase Android System?

Well, Manifest and Context… it seems that looking at one, reveals a lot about the other; but also looking at both can lead to a far better understanding about how apps are coupled with the Android System.

What happens when you install an Android App?

When you install an application, the app is given its own unique Linux User ID and runs on its own instance of the Android Runtime. Thus, each application is completely isolated with all its resources inaccessible to every other app.

This rule not only gives birth to the concept of “permissions”, but it also makes you realise that since your application is that much isolated, it depends heavily on the Android System to provide any resources and perform tasks on behalf of your app.

Thus, your app does not just access parts of the OS by itself, but instead, it asks the OS to provide any associated resources and accomplish tasks on its behalf.

Such a strict model assures a more secure, better structured, and less error-prone application because we leave much of the responsibility to the OS itself, rather than to our code.

But if the Android System is that restrictive to our apps, that raises two issues that need to be addressed.

  1. We should have a way to communicate with the Operating System, in order to request things we are otherwise limited from accessing or launching by ourselves (addressed by Context).
  2. The Operating System should be aware of every app’s components existence, in order to launch or access them when requested (addressed by Manifest).

App Manifest

Any Android Developer should be aware of the existence of the AndroidManifest XML in Android, which in fact is very closely related to the Android Context, and we will see why soon enough.

When we create an application, the Android System really knows nothing about it, unless listed in the App Manifest file. Even to have the app’s icon at the App Drawer, we need to declare an activity to be the launching activity via an implicit intent declaration (using “intent-filter”) in the manifest.

Now, inside the <manifest> tag of the AndroidManifest.xml you declare

  1. package information about your app, so it can be identified by the Android OS,
  2. permissions using the <permission> tag,
  3. and any descendant implementation of the four application componentsclasses you wrote in your app, declared through the tags
    <activity> for Activities,
    <service> for Services,
    <provider> for Content Providers, and
    <receiver> for Broadcast Receivers.

Now, there is a reason we call descendants of these four classes “the four application components”. That’s because out of all the classes we define in our code, only descendant classes of these four components can make it inside the manifest (through the equivalent tags), in order for the OS to become aware of their existence.

So, in the manifest, we declare things that the Android needs to be aware about the Application, in order for it to provide functionalities that cannot be handled by application code alone.

You see, “permissions” is one thing, so Android knows what hardware and software resources should be enabled to your app’s unique user. So when that user runs your app, the android system will allow access to the permitted resources through its APIs.

Other manifest declarations include the implementations of the four components (we just talked about) in your app, which you want Android to be aware of.

Let’s talk intents

When you make an explicit intent from some activity (Activities are Context descendants) to open another activity, you never create the new activity object and pass variables to its constructor. Instead, what the explicit intent does, is to ask the android to create and launch the target activity on your behalf and pass a bundle with data (rather than passing constructor parameters), and this is what an explicit intent really is.

On the other hand, when you make an implicit intent, you don’t really know what activity will handle your request. The Android System based on every apps’ Manifest declarations, will figure what set of activities (or other component types) can handle your “intention”.

So intents, are in fact “intentions”. They are requests to the Android System to take some action based on something you intend to happen, which cannot otherwise be done directly with code.

And this is possible only if Android has a log of all the available components of every installed application (thanks to every app’s manifest), in order to act accordingly.

“Intents” is the Android’s way to have a Context (which is discussed later) ask the OS to to step up and perform actions on behalf of your app (like starting other activities, services, or delivering a brodcast).

  • Activities & Manifest: Android is aware of all the activities that can be launched implicitly or explicitly, thanks to the registered activities entries at every manifest out there

Content Providers (Not Context descendants) manage access to a central repository of data. You can use content providers to provide data within your own app or to provide data to other apps (like your phone’s contacts list).

  • Content Providers & Manifest: Android is aware of all the content providers, so it can provide content to your app or other apps when needed, thanks to the manifest declarations.

Broadcast Receivers (Not Context descendants) are there to receive broadcasts made by some android service or application.

  • Broadcast Receivers & Manifest: Android is aware of all applications registered to listen to a broadcast even when the app is not running, since it knows from all apps manifests which applications` receivers should be notified per specific broadcast type.

Side Note: It is not obligatory to define Broadcast Receivers in the manifest. You see, you can either dynamically register an instance of this class with Context.registerReceiver() or statically declare an implementation in your AndroidManifest.xml with the <receiver> tag. The cool thing about it is that if you register the receiver at runtime via registerReceiver(), it will “listen” to broadcasts during the time you asked it to “listen”, however, if you define it at the manifest, it will have a more permanent role, listening mostly all the time.

Services (they are Context descendants) are the final type of application component, that can perform long-running operations in the background. It does not provide a user interface. Once started, a service might continue running for some time, even after the user switches to another application.

  • Services & Manifest: Android is aware of all the available services through every app’s manifest declarations so it knows what it can run.

So, these four application components when declared at the manifest, they let the Android OS know they are there, so it can take action when some request by your app (or some other app) fits their existence.

What is Android Manifest — TL;DR

The manifest informs the Android System of the application’s own existence, any permissions needed, and of app components, your code cannot handle directly. This model allows for a richer app experience thanks to other applications’ manifest declarations that expose components, your app can make use of, on top of its own.

Context & Non-Context Manifest Components

Before talking about the context (which follows next), we should make clear that not all manifest entries are context object descendants.

  • “Context manifest components” are Context class descendants.
  • “Non-Context manifest components” are non-context descendants (instead they consume a context).

CONTEXT Manifest components rely on the android environment and need to be “wired” to the Android System accordingly.

They perform UI or background operations. They are more active by nature, and they represent complex launchable structures that represent “application state”. This “state” is managed by the Android OS and is resembled in your app through these very objects (which are context descendants).

These can be of the following:

  • Application
  • Activity
  • Service

NON-CONTEXT Manifest components represent objects that employ some context to get a job done; they are not “context descendants” themselves.

They are more “passive” by nature, “responding” to requests via a supplied context, performing a standardized functionality, and they don’t represent “application state”.

  • Content Providers

When you want to access data in a content provider, you use the ContentResolver object in your application’s Context to communicate with the provider as a client.

That is, with Content Providers, we use the Application Context as a communication vehicle to be provided with the desired content.

  • Broadcast Receivers

Base class for code that receives and handles broadcast intents sent by Context.sendBroadcast(Intent)

That is, from a broadcast, which was delivered to the Android System via a context (by your app, another app, or system service), the Android will notify all the receivers registered to listen to that broadcast.

Android Context

Google Definition:

Interface to global information about an application environment. This is an abstract class whose implementation is provided by the Android system. It allows access to application-specific resources and classes, as well as up-calls for application-level operations such as launching activities, broadcasting and receiving intents, etc.

Now you got a better grasp of the manifest, you realise that since all interaction between application components — even internally to your own app — has to go via the Android System, and not directly from inside your code, you need a handle to the android system. That handle comes in the form of an android context.

So, the Android Context will act as an OS intermediary between your app and android, but also as a resource provider for your own app’s resources.

Yes, the resources too are also not directly available to you. Instead, they are declared in the predefined “res” folder, which the android knows how to find for every app through a numeric id that is given at compile-time, for every resource. Then the android system provides that resource’s content via the context, rather than giving you access to the raw resource through the file system.

So, the Android Context provides anything that your app cannot access or handle by itself, including global device information, like if your phone is in portrait or landscape mode, and more…

Where can I find the context?
Since the ActivityService, and Application classes are Context class descendants (as you see by clicking the above links), you can pass instances of these classes as your actual context. That directly signifies that passing an activity as context (as the android handle) to something that is related to the entire app, when that activity is destroyed, you will be introduced to a memory leak. You see, in that case, this activity won’t get destroyed because we hold a reference to it (thus memory leak)…

Wait, what?
Why not just always use the application context instead, since all we need is a handle to android? Why have different life cycled contexts?

  • Activity inherits from ContextThemeWrapper, while Service and Application do not (see that “Theme” word in that class?). So you see that ApplicationContext is not UI related, so it cannot be used to inflate layouts, start other activities, or display dialogues.
  • Also, depending on what context we pass, we get access to different information about the application’s environment (take a look at this awesome video from Coding in Flow — also look at this article about ContextThemeWrapper).
  • Now for other tasks, like for a non-UI singleton object that will be used throughout the application, and requires context (like access to a database) you will use ApplicationContext to avoid memory leaks because you will hold the same database reference throughout the application lifetime.

Here is a nice article about the different lifecycled contexts

So, whenever you try to do something that needs the Android OS to act as an intermediary, in order to fetch global information, resources, perform tasks, or provide content, that cannot be handled directly by your code, you will have some method call that requires passing the equivalent context, for Android to handle your job, rather than handling it yourself.

Here is a very good overall video on Android Context

The three shades of Context

Passing a context in method calls in Android is very frequent. However, the fact that you may pass a context for completely different reasons, is a major source of confusion for new developers, as the context’s role is not clear.

So, when you include a context in a method call, the context might play one of the following three roles:

  1. Passive Role: To ask the OS for some value (eg: what is the value of a resource).
  2. Active Role: To ask the OS to perform some action on your behalf (eg: launching a component through an Intent, inflate some layout, display a message, etc).
  3. Wiring Role: To connect your app to a distant entity managed by the OS (eg: connection to an SQLite database, where that wire will be used in both “active” and “passive” roles to read or update data in the database — in such cases you almost always use an Application Context, as such a “wire” you want it to exist throughout the lifetime of the entire app).

In any case, a context is always the OS intermediary that stands between your code and the Android System, delivering requests in order for some information to be retrieved or for some action to take place.

So the next time you use a “context” in a method call, you will know it is the vehicle that will reach the OS and ask it to execute or retrieve your method’s request.

What is Android Context — TL;DR

The Context is a handle to the Android System that can provide system information, resources, but also will act as an intermediary that glues different parts of your application, or components of other apps or services that can handle your requests.

It provides anything that needs to be handled by the OS, and not possible to be handled directly by your code.

Testing & Design Patterns

Now you know why the context exists, you will appreciate the difference between local and instrumented tests.

In a nutshell, local tests do not require some interaction with the Android OS, while the integration tests require the involvement of the Android OS in order to complete. Instrumented tests need to run on an emulator or real device, making them significantly slower than local tests.

Instrumented tests are usually required when you need to perform something that involves heavily the OS through some context, or if you are testing context descendant classes (like an Activity).

As a side-note, for simple cases where you just need a context that doesn’t require deep involvement of the OS (such as UI related stuff), there are ways to mock a context and avoid running instrumented tests — but this is out of this article’s scope.

With all that in mind, with design patterns like the MVVM (Model-View-ViewModel), which is endorsed by Google, you can keep all the Business Logic in the ViewModel. Now in your tests (if you provide a mock repository with sample data), you can completely isolate the ViewModel from the UI and the Data Layers, being able to test your ViewModels with local rather than instrumented tests.

But a necessary step in order to achieve that is understanding what part of your code really depends on the Android OS, and what does not.

So, knowing the way your app is coupled with the Android System allows you to appreciate even further the logic behind design patterns and testing.

Find more about testing here: https://developer.android.com/training/testing/fundamentals