[8] Android Context - mariamaged/Java-Android-Kotlin GitHub Wiki

Android - Context

MainActivity extends AppCompatActivity, which extends Activity, which implements the Context interface.

1. Where Did It Come From?

  • In mid-2000, the dominant form of Java programming was for server-side Web development, using:
    • Servlets.
    • WARs.
    • And so on.
  • In Web development, there is often some form of a "session" object.
    • At minimum, this object represents the user's session with the server and represents a a place where the servlet can stash values from one request that might be used in a subsequent request from the same user.
       
  • In Android, a lot of functionality routes through a Context, either because:
    • Our only ways of accomplishing a particular thing involve functions on a Context.
    • Our only way to get at some other object that accomplishes that thing is by calling a function on the Context.

2. The Major Types of Context

  • Context is an interface, so in theory anything could be a Context.

2.1 Context from Components

  1. Activity.
    • Implements Context.
    • We can call getString() on.
  2. Service.
    • Implements Context.
  3. BroadcastReceiver.
    • Where you get a Context via its onReceive() function that you implement or inherit.
  4. ContentProvider.
    • Where you get a Context by calling getContext() when you need one.

2.2 Application

  • There is one other "root" Context besides your components: Application.
  • Each Android app has an Application singleton.
    • This object is created when the process is created, and it lives through the life of that process.
  • In your regular application code, you get access to this singleton: by calling getApplicationContext() on some other Context.

3. Instrumented Tests

Note that in testing we get a Context in other ways.

Kotlin

package com.mariamaged.helloworld
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4

import org.junit.Test
import org.junit.runner.RunWith

import org.junit.Assert.*

@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
	@Test
	fun useAppContext() {
		val appContext = InstrumentationRegistry.getInstrumentation().targetContext
		assertEquals("com.mariamaged.helloworld", appContext.packageName)
	}
}

Java

package com.mariamaged.helloworld;

import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.*;

@RunWith(AndroidJUnit.class)
public class ExampleInstrumentedTest {
	@Test
	public void useAppContext() {
		Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
		
		assertEquals("com.mariamaged.helloworld", appContext.getPackageName());	
	}
}

3. Key Context Features

  • Many things take a Context.
  • Constructors for all of our widgets and containers, for example, take a Context as a parameter.

3.1 Access to Resources and Assets

Resources
  • If you want to (1) get the value or (2) otherwise use a resource, you will wind up using a Context.
  • Sometimes, that comes from calling convenience functions on Context functions, such as getString().

In general, though, access to resources comes from a Resources object, and you get one of those by calling getResources() on a Context.

Resources has functions to retrieve most types of resources:

  • Strings.
  • Dimensions.
  • Colors, and so on.
  • The convenience functions on Context simply delegate to the Resource object- for example, getString() on Context just forwards your request to getString() on Resources.

Assets
  • In addition to resources, an Android app can also have assets, found in assets/ directory that sits alongside directories like src/ and res/.
  • If you package assets this way with your app, calling getAssets() on a Context gives you an AssetManager.
  • From there, you can work with the assets, such as by calling open() to get an InputStream from which you can read an asset's content.

3.2 Access to Root Directories

  • Resources and assets are packaged with the app.
  • Beyond those, we have the ability to write to files on the local filesystem and read them back later.
  • On the whole, this is standard I/O using Java classes like:
    • File.
    • InputStream.
    • OutputWriter.

The big limitation is where we can read and write.

3.3 Access to System Services

  • Lots of stuff used by your app is actually managed outside of your app.
  • For example, suppose that you want to find out the device's location.
    • Your app code does not work with GPS hardware directly.
    • Instead, it will work with a LocationManager, or something that wraps around a LocationManager.
    • LocationManager: is a "System Service", and in turn will talk to other parts of the OS that, eventually, work with the GPS hardware.

Whenever you need access to a "system service", the typical approach to get one is to call getSystemService() on a Context.

  • Occasionally, there will be other approaches:
    • Some system services have a function that you can use to get an instance by way of a Context, such as LayoutInflator.from().
    • Some system services have convenience functions on Context, such as getPackageManager() to get a PackageManager instance.

4. Know Your Context

As your app grows, you will start to having classes that are not Android components and do not have direct access to some Context.

  • Instead, they will be talking with your Web Services.
  • Or storing things in a local database.
  • Or performing any number of other tasks that are important for your app.
  • In an ideal world, few of these classes will need a Context.
  • For those that do, you will need to decide what Context they will use:
Use Choice
Do they take a Context as a function parameter for a particular operation. So the caller chooses the Context.
Do they take a Context as a constructor parameter. So the choice of Context has to take into account how long this object is needed.
Do they do something more elaborate. Such as dependency injection.