Context, we deal with it every day when we write Android applications, but do we really understand it?

Let me ask you a question to see how you respond:

What is the Context? What does it do?

It describes information about an application environment through which we can retrieve application resources and classes. It also includes application-level actions such as starting an Activity, sending a broadcast, receiving an Intent, and so on.

But that’s a little vague. Can you be more specific? What application environment information does it describe and what classes of operations does it provide?

So let’s take a look at the Context and its family.

What is the Context

Let’s take a look at Google’s official 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. */Copy the code

Translation:

  1. It is an interface to global information about the application environment.
  2. This class is an abstract class, and the Android system provides a concrete implementation class of this abstract class.
  3. Allows access to application-specific resources and classes, as well as upward invocation of application-level operations, such as starting an Activity, broadcasting and receiving intents.

In essence, Context only defines a basic set of functional interfaces; it is not responsible for implementation. And who is responsible for making it happen?

Before we answer that question, let’s take a look at the Context family.

The Context family

We know that Activity, Application, and Service are all subclasses of Context. Are there any other subclasses of Context, what’s their inheritance?

Let’s look at the inheritance of the related classes of context:

The class diagram shows three classes that we don’t see very often, so let’s start by recognizing them:

ContextImpl: Implementation class of the Context API that provides the basic Context objects for activities and other application components.

ContextWrapper: A proxy implementation of a Context that delegates only all of its calls to another Context. You can subclass to modify the behavior without changing the original Context.

ContextThremeWapper: New ContextWrapper with the specified theme.


ContextImpl, ContextWrapper, ContextImpl, ContextWrapper

This has to start from the design pattern, we first to understand a design pattern ———— decorator pattern.

Decorator pattern: Dynamically add additional responsibilities to an object. To extend functionality, decorators offer a more flexible alternative to inheritance. It usually consists of four parts: -Component: Abstract class or interface, which is the interface or inherited base class that both decorator and decorator need to implement. - Decorator character, usually an abstract class that defines a private variable to refer to Component. -ConcreteDecotator: Decorator concrete implementation classes, some that implement some functionality in methodsCopy the code

How do you understand the decorator pattern applied to the Context?

ContextImpl is the basic implementation of the interface defined by the Context. Any Application, Service, or Activity has these common features or business requirements. ContextWrapper is the decorator role, which defines a mBase variable that refers to the ContextImpl class. The ContextWrapper subclass is the implementation class of the decorator, which extends additional functionality without changing the ContextImpl class. This ensures that the design has both extensibility and open – close principles.

Context

Let’s take a look at Context, what methods it has, and for space reasons, I’m just going to give you a few methods, but I’m not going to list some common methods.

First — access to application resources, properties, and classes


int getNextAutofillId()

This method is used to automatically generate ids, and none of the returned ids will be repeated.


ApplicationInfo getApplicationInfo()

Returns complete application information for this context package. ApplicationInfo’s data structure is as follows:

Public Class ApplicationInfo extends PackageItemInfo implements Parcelable {// The default task Affinity for all activities in an application, TaskAffinity public String taskAffinity; // Optional, access all components of the current application need to declare permission, from the "Android :permission" property public String permission; // From the "Android :process" property, specify the application running process name. If this parameter is not specified, the application package name is used by default. public String processName; Public String className; // Application descriptionRes public int descriptionRes; //application theme resource id public int theme; / /, from "android: manageSpaceActivity" attribute is used to specify an Activity to manage the data, / / it will eventually appear in the Settings - > applications management, the default button for a "clear data", specify the attribute, This button can be clicked to jump to the // Activity and let the user choose which data to erase. If this parameter is not set, the value is null. Public String manageSpaceActivityName; // The class that implements the backup function of the application. The value of backupAgent in the configuration file. // If Android :allowBackup is set to false, ignore this property public String backupAgentName; // An optional property indicating that the application supports automatic backup of application data // The default value is 0, indicating that the entire data folder of the application will be backed up + managed external storage space. // Any negative value indicates that the application does not support full data backup, although it may still want to participate through the traditional key/value backup API; Include /exclude policy @unsupportedAPPUSage public int fullBackupContent = 0; Android: UIOptions public int UIOptions = 0; android: UIOptions public int UIOptions = 0; / / the shortest dimension of screen space required, specific please refer to the android: requiresSmallestWidthDp attribute public int requiresSmallestWidthDp = 0; // The maximum aspect ratio supported by the application public float maxAspectRatio; // Application apk full path public String sourceDir; // Public resource path public String publicSourceDir; // Names of all installed split APKs, in dictionary order public String[] splitNames; // Zero or more full paths to split APKs, in lexicographical order public String[] splitSourceDirs; // Paths to all shared libraries linked to by this application. public String[] sharedLibraryFiles; Public List<SharedLibraryInfo> sharedLibraryInfos; // The full path to the default directory specified for the package's persistent data. public String dataDir; // The full path to the device protection directory allocated for the packet's persistent data. public String deviceProtectedDataDir; // The credentials allocated for the package's persistent data protect the full path of the directory. @SystemApi public String credentialProtectedDataDir; // The full path to the directory where the native JNI library is stored. public String nativeLibraryDir; // If this application does not require any specific ABI, its value will be null @unsupportedAPPUSAGE Public String primaryCpuAbi; // The kernel user ID assigned to this application; This is not a unique ID (multiple applications can have the same UID) public int UID; Public long longVersionCode; Public int networkSecurityConfigRes; // The version of the sandbox in which the application is to run. @SystemApi public int targetSandboxVersion; AppComponentFactory public String appComponentFactory; / / com. Android. Internal. R.s. Tyleable AndroidManifestProvider_icon resource id public int iconRes; }Copy the code

UserHandle getUser()

Gets the user associated with this context.

The user on the device is represented by the UserHandle class. There are three concepts in UserHandler that need to be recognized:

Userid: indicates the UID of a Linux user

Appid: App-related. Appids with the same package name are the same for different users.

Uid: This is not a Linux UID, but an Android unique UID. Android4.2 only started supporting multiple users, but by this time Linux’s uid/gid multi-user system was already in use for App management, causing conceptual confusion. This UID is generated by the userID and appID. The algorithm is userID / 100000 + appID % 100000.


IBinder getActivityToken()

Get the Activity Token as described in the method name.

What is an Activity Token?

Say the conclusion directly, the process of specific analysis does not stick. The Activity Token is an IBinder object. The actual implementation subclass is the LocalActivityRecord class. The fields of this class are as follows:

final String id;                // Unique name of this record.
Intent intent;                  // Which activity to run here.
ActivityInfo activityInfo;      // Package manager info about activity.
Activity activity;              // Currently instantiated activity.
Window window;                  // Activity's top-level window.
Bundle instanceState;           // Last retrieved freeze state.
int curState = RESTORED;        // Current state the activity is in.
Copy the code

The Activity Token is an Activity Token.


The second type — calls application-level operations up


Object getSystemService(@ServiceName @NonNull String name)

Returns a handle to the system-level service by name. The class of the returned object varies depending on the name of the request.

The getSystemService method eventually retrieves a cache object from SystemServiceRegistry and returns it to the application.

When the SystemServiceRegistry class is initialized, all system services are registered and cached with an ArrayMap.


void startActivityAsUser(@RequiresPermission Intent intent, @Nullable Bundle options, UserHandle userId)

Allows an Activity to be started with the specified user. This method does not work for applications that are not preinstalled on the system image.


void startIntentSender(IntentSender intent, @Nullable Intent fillInIntent, @Intent.MutableFlags int flagsMask, @Intent.MutableFlags int flagsValues, int extraFlags, @Nullable Bundle options)

Similar to startActivity(Intent, Bundle), but started with IntentSender. If IntentSender is used for an Activity, the Activity will start, just as if you called startActivity (Intent). Otherwise, its associated operation (such as sending a broadcast) will be performed as if you had called IntentSender.sendentent.

IntentSender’s official explanation is as follows:

Description of the Intent and target Action to execute. The returned objects can be handed to other applications so that they can later perform the described operations on your behalf.Copy the code

void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions)

Sends a broadcast with a set of permissions that can only be received by recipients who have declared the same permissions.


startInstrumentation(@NonNull ComponentName className, @Nullable String profileFile, @Nullable Bundle arguments)

Begin to execute android. App. Instrumentation class. The given Instrumentation component kills the target Application(if it is running), starts the target process, instantiates the Instrumentation component, and then lets it drive the Application.