Design of Application Context

Basically, each application will have its own Application, which inherits from the Application class of the system, and then encapsulates some common operations in its own Application class. In fact, this is not a recommended practice for Google, because we just use Application as a general tool class, and in fact use a simple singleton class can achieve the same function. But according to observation, there are too many projects using Application in this way. Of course, this approach does not have any side effects, but it just shows that many people still have some deficiencies in understanding the application. So here we will first analyze the design of Application, tell some details that you do not know, and then look at the usual use of Application.

First create a new MyApplication and inherit it from Application, then specify MyApplication in the Android Manifest.xml file, as follows:
<application  
    android:name=".MyApplication"  
    android:allowBackup="true"  
    android:icon="@drawable/ic_launcher"  
    android:label="@string/app_name"  
    android:theme="@style/AppTheme" >  
    ......  
</application

When the assignment is completed, when our program starts, the Android system creates an instance of MyApplication, and if it is not specified here, an instance of Application will be created by default.

As mentioned earlier, many applications are now used as generic tool classes, so how can we get instances of them as a generic tool class? As follows:
public class MainActivity extends Activity { 
        @Override 
        protected void onCreate(Bundle savedInstanceState) { 
                   super.onCreate(savedInstanceState); 
                   setContentView(R.layout.activity_main); 
                    MyApplication myApp = (MyApplication) getApplication(); 
                   Log.d("TAG", "getApplication is " + myApp); 
            } 
}

As you can see, the code is very simple, just call the getApplication() method to get an example of our custom Application. The print result is as follows:


In addition to the getApplication() method, there is actually a getApplicationContext() method. These two methods seem to be somewhat related, so what's the difference between them? Let's modify the code:
public class MainActivity extends Activity {  
      
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        MyApplication myApp = (MyApplication) getApplication();  
        Log.d("TAG", "getApplication is " + myApp);  
        Context appContext = getApplicationContext();  
        Log.d("TAG", "getApplicationContext is " + appContext);  
    }  
} 

Similarly, we print out the result of getApplicationContext() and now rerun the code as shown in the following figure:
So why does Android offer two ways to duplicate functionality, since the results of both methods are the same? In fact, the two methods are quite different in scope. The getApplication() method is very semantical, and it is known to be used to obtain application instances at first glance, but this method can only be invoked in Activity and Service. Maybe in most cases we use Application in Activity or Service, but if we want to get an instance of Application in some other scenarios, such as Broadcast Receiver, we can use the getApplicationContext() method, as follows:

public class MyReceiver extends BroadcastReceiver {  
  
    @Override  
    public void onReceive(Context context, Intent intent) {  
        MyApplication myApp = (MyApplication) context.getApplicationContext();  
        Log.d("TAG", "myApp is " + myApp);  
    }  
}  

In other words, the getApplicationContext() method has a wider scope. Any instance of a Context can get our Application object by calling the getApplicationContext() method.

 
The getBaseContext() method gets a ContextImpl object. Does this ContextImpl feel a little familiar? Let's go back to the inheritance structure diagram of Context. ContextImpl is the implementation class of the context function. That is to say, classes such as Application and Activity do not actually implement the functions of Context, but only do a layer of interface encapsulation. The specific functions of Context are accomplished by the ContextImpl class. So how does this design work? Let's take a look at the source code. Because Application, Activity and Service are directly or indirectly inherited from ContextWrapper, we can directly look at the source code of ContextWrapper, as follows:
  1 /** 
  2 * Proxying implementation of Context that simply delegates all of its calls to 
  3 * another Context.  Can be subclassed to modify behavior without changing 
  4 * the original Context. 
  5 */  
  6 public class ContextWrapper extends Context {  
  7     Context mBase;  
  8       
  9     /** 
 10      * Set the base context for this ContextWrapper.  All calls will then be 
 11      * delegated to the base context.  Throws 
 12      * IllegalStateException if a base context has already been set. 
 13      *  
 14      * @param base The new base context for this wrapper. 
 15      */  
 16     protected void attachBaseContext(Context base) {  
 17         if (mBase != null) {  
 18             throw new IllegalStateException("Base context already set");  
 19         }  
 20         mBase = base;  
 21     }  
 22   
 23     /** 
 24      * @return the base context as set by the constructor or setBaseContext 
 25      */  
 26     public Context getBaseContext() {  
 27         return mBase;  
 28     }  
 29   
 30     @Override  
 31     public AssetManager getAssets() {  
 32         return mBase.getAssets();  
 33     }  
 34   
 35     @Override  
 36     public Resources getResources() {  
 37         return mBase.getResources();  
 38     }  
 39   
 40     @Override  
 41     public ContentResolver getContentResolver() {  
 42         return mBase.getContentResolver();  
 43     }  
 44   
 45     @Override  
 46     public Looper getMainLooper() {  
 47         return mBase.getMainLooper();  
 48     }  
 49       
 50     @Override  
 51     public Context getApplicationContext() {  
 52         return mBase.getApplicationContext();  
 53     }  
 54   
 55     @Override  
 56     public String getPackageName() {  
 57         return mBase.getPackageName();  
 58     }  
 59   
 60     @Override  
 61     public void startActivity(Intent intent) {  
 62         mBase.startActivity(intent);  
 63     }  
 64       
 65     @Override  
 66     public void sendBroadcast(Intent intent) {  
 67         mBase.sendBroadcast(intent);  
 68     }  
 69   
 70     @Override  
 71     public Intent registerReceiver(  
 72         BroadcastReceiver receiver, IntentFilter filter) {  
 73         return mBase.registerReceiver(receiver, filter);  
 74     }  
 75   
 76     @Override  
 77     public void unregisterReceiver(BroadcastReceiver receiver) {  
 78         mBase.unregisterReceiver(receiver);  
 79     }  
 80   
 81     @Override  
 82     public ComponentName startService(Intent service) {  
 83         return mBase.startService(service);  
 84     }  
 85   
 86     @Override  
 87     public boolean stopService(Intent name) {  
 88         return mBase.stopService(name);  
 89     }  
 90   
 91     @Override  
 92     public boolean bindService(Intent service, ServiceConnection conn,  
 93             int flags) {  
 94         return mBase.bindService(service, conn, flags);  
 95     }  
 96   
 97     @Override  
 98     public void unbindService(ServiceConnection conn) {  
 99         mBase.unbindService(conn);  
100     }  
101   
102     @Override  
103     public Object getSystemService(String name) {  
104         return mBase.getSystemService(name);  
105     }  
106   
107     ......  
108 }  
ContextWrapper

Since there are still many methods in ContextWrapper, I did some screening and only posted some of them. So these methods are very familiar to everyone, getResources(), getPackageName(), getSystemService(), and so on are the methods we often use. So what are the implementations of all these methods? In fact, all the implementations of methods in ContextWrapper are very uniform, that is, the method corresponding to the previous method name in the mBase object is called.

So what is this mBase object? Look at the attachBaseContext() method in line 16, which passes in a base parameter and assigns it to the mBase object. The attachBaseContext() method is actually called by the system. It passes the ContextImpl object as a parameter to the attachBaseContext() method and assigns the value to the mBase object. Then all the methods in ContextWrapper are actually implemented by the ContextImpl through this delegation mechanism, so Cont. ExtImpl is an implementation class of context functionality that is very accurate.

 
Then take another look at the getBaseContext() method we just printed, on line 26. This method has only one line of code, that is, it returns the mBase object, which is actually the ContextImpl object, so the print result has been verified.

  

Keywords: Java Android Google xml

Added by sungpeng on Thu, 11 Jul 2019 21:54:53 +0300