Android - application context Context

1 Introduction

Context is a general parent class of Android. Starting the four major components, obtaining resources, and obtaining class loaders are all done through Context. Activity, Service, and Application are also derived from Context.

  • Is the interface to global information about the application environment.
  • Is an abstract class provided by the Android system.
  • Allows access to application-specific resources and classes, as well as invoking application-level operations such as launching activities, broadcasting and receiving intents, and more.

Context is a core functional class that maintains the normal operation of each component of the Android program, and this core functional class is equivalent to a large environment. Only in this environment can Android resources be obtained and various components of Android can be called.

To put it in a popular way: Android applications are like a movie. The four major components of Android are equivalent to the four protagonists of the movie, and the Context is equivalent to the camera lens. Only through the camera lens can we see the four protagonists. The protagonist is pre-determined, and cannot be newly created casually. And other walk-on ones are not predetermined, that is to say, they are not so important. They can be new, but they also need to be seen through the camera lens, so there is Button mButton=new Button (Context).

Class Diagram

  • Context: an abstract class that defines the top-level interface
  • ContextImpl: the implementation class of Context
  • ContextWrapper: The wrapper class of Context, the member variable mBase is always pointing to the object of ContextImpl
  • ContextThemeWrapper: a subclass of ContextWrapper, including Theme-related operations

The three types of Context, Activity, Service, and Application, are common in most cases, but for security reasons, in some cases, they cannot be common, such as starting an Activity, popping up a Dialog, and so on. The startup of an Activity must be based on another Activity; the Dialog must also pop up on the Activity. In these cases, only the Context of the Activity can be used.

That is to say: everything related to UI should be handled with Activity as Context; other operations, Service, Activity, Application and other instances can be used, as shown in the figure below: Note that some NOs have added
insert image description here
some Numbers, in fact, these are YES in terms of ability, but why is it said to be NO? Let's explain one by one:

Number 1: Starting the Activity is possible in these classes, but a new task needs to be created. Generally not recommended.

Number 2: It is legal to layout inflate in these classes, but the default theme style of the system will be used. If you customize some styles, they may not be used.

Number 3: Allowed when the receiver is null, used to get the current value of the sticky broadcast in version 4.2 or above. (can be ignored)

Note: The reason why ContentProvider and BroadcastReceiver are in the above table is that there is a context for use in their internal methods.

2. Tips

2.1 Number of Contexts

Context quantity = Activity quantity + Service quantity + 1 (Application)

2.2 The relationship between getApplication(), getApplicationContext() and getBaseContext()

Get the three methods of printing separately in Activity:

MyApplication myApp = (MyApplication) getApplication();  

Context appContext = getApplicationContext();  

Context baseContext = getBaseContext();

Print result:

getApplication::::com.beidou.mvptest.MyApplication@53502fac

getApplicationContext::::com.beidou.mvptest.MyApplication@53502fac

baseContext::::android.app.ContextImpl@53505ce4

in conclusion:

  • What getApplication and getApplicationContext get is an object MyApplication.
  • What getBaseContext gets is ContextImpl.

doubt:

The objects obtained by getApplication and getApplicationContext are the same, so why design two methods?

  • The scope of the two is different, and the latter is more applicable than the former. getApplication is only applicable to Activity and Service, while getApplicationContext is also used in other scenarios, such as BroadcastReceiver.

What is ContextImpl?

  • ContextImpl is the implementation class of Context function. Application, Service, and Activity do not realize the functions of Context, but only encapsulate the interface, and the specific functions are completed by ContextImpl.
  • Because Application, Activity, and Service are all directly or indirectly inherited from ContextWrapper, we can directly look at the source code of ContextWrapper, and we will find that the implementation of all methods in ContextWrapper is very uniform, that is, the method corresponding to the current method name in the mBase object is called.
  • So what is this mBase object? Let's look at the attachBaseContext() method on line 16. In this method, a base parameter is passed in, and this parameter is assigned to the mBase object. The attachBaseContext() method is actually called by the system. It will pass the ContextImpl object as a parameter to the attachBaseContext() method, and then assign it to the mBase object. After that, all the methods in the ContextWrapper are actually handed over through this delegation mechanism. It is implemented by ContextImpl, so ContextImpl is the implementation class of the context function.
  • Look again at the getBaseContext() method we just printed, on line 26. This method has only one line of code, which just returns the mBase object, and the mBase object is actually the ContextImpl object, so the printing result just now has also been confirmed.

2.3 Problems and solutions when using Application

2.3.1 Get various methods of the Context implementation class in the construction method of Application

public class MyApplication extends Application {
    
      
      
    public MyApplication() {
    
      
        String packageName = getPackageName();  
        Log.d("TAG", "package name is " + packageName);  
    }  
      
}

operation result:

空指针:

java.lang.RuntimeException: Unable to instantiate application 

com.example.test.MyApplication: java.lang.NullPointerException

Revise:

public class MyApplication extends Application {
    
      
      
    @Override  
    public void onCreate() {
    
      
        super.onCreate();  
        String packageName = getPackageName();  
        Log.d("TAG", "package name is " + packageName);  
    }  
      
}  

The operation result is normal! What happened? Looking back at the source code of ContextWrapper, there is an attachBaseContext() method in ContextWrapper, which assigns an incoming Context parameter to the mBase object, and then the mBase object has a value. And we know that all the methods of Context call the method of the same name of this mBase object, that is to say, if you call any method in Context before the mBase object has been assigned, a null pointer exception will occur . The execution order of methods in Application:
insert image description here
It is recommended to initialize global variable data in the onCreate() method. If you want to advance the initialization to the extreme, you can also rewrite the attachBaseContext() method:

public class MyApplication extends Application {
    
      
      
    @Override  
    protected void attachBaseContext(Context base) {
    
      
        // 在这里调用Context的方法会崩溃  
        super.attachBaseContext(base);  
        // 在这里调用Context的方法就没问题
    }  
}  

2.3.2 When using Application as a tool class, the new method is used to obtain instances

public class MyApplication extends Application {
    
      
      
    private static MyApplication app;  
      
    public static MyApplication getInstance() {
    
      
        if (app == null) {
    
      
            app = new MyApplication();  
        }  
        return app;  
    }  
}  

The method of new MyApplication instance, the obtained object does not have the ability of Context, if the Context operation is performed, a null pointer will be reported, because it is just a java object. And we know that Application itself is a singleton, so we can just return itself directly, instead of going to the new object to get an instance, otherwise it will be self-defeating.

public class MyApplication extends Application {
    
      
      
    private static MyApplication app;  
      
    public static MyApplication getInstance() {
    
      
        return app;  
    }  
      
    @Override  
    public void onCreate() {
    
      
        super.onCreate();  
        app = this;  
    }  
      
}  

2.4 Problems and Solutions of Memory Leaks Caused by Context Misuse

package com.mooc.shader.roundimageview;
 
import android.content.Context;
 
public class CustomManager
{
    
    
	private static CustomManager sInstance;
	private Context mContext;
 
	private CustomManager(Context context)
	{
    
    
		this.mContext = context;
	}
 
	public static synchronized CustomManager getInstance(Context context)
	{
    
    
		if (sInstance == null)
		{
    
    
			sInstance = new CustomManager(context);
		}
		return sInstance;
	}
	
	//some methods 
	private void someOtherMethodNeedContext()
	{
    
    
		
	}
}

There is no problem with writing this way. The problem is that we cannot be sure where this Context comes from. It is very likely that you directly passed this in a certain Activity for convenience; this is where the problem comes. Our class The sInstance in is a static and strong reference, and an Activity is referenced inside it as the Context. That is to say, as long as our Activity is alive, there is no way for our Activity to perform memory recovery. And the life cycle of our Activity must not be so long, so it caused a memory leak.

So, how can we avoid such problems?

Some people will say, we can use soft references, um, soft references, if they are recycled, aren't you afraid of NullPointException?

Modify the above code as follows:

public static synchronized CustomManager getInstance(Context context)
	{
    
    
		if (sInstance == null)
		{
    
    
			sInstance = new CustomManager(context.getApplicationContext());
		}
		return sInstance;
	}

In this way, we have solved the problem of memory leaks, because we are referring to an ApplicationContext whose life cycle is consistent with our singleton object.

2.5 Attention

Generally, memory leaks caused by Context are almost always destroyed when the Context is destroyed, but the destruction fails because it is referenced. The Context object of the Application can be understood as existing with the process, so we conclude the correct posture of using the Context:

  • When the Context of the Application can be handled, and the object with a long life cycle, the Context of the Application is used first.
  • Do not allow objects with a lifetime longer than the Activity to hold a reference to the Activity.
  • Try not to use non-static inner classes in Activity, because non-static inner classes will implicitly hold references to external class instances. If you use static inner classes, use external instance references as weak references.

Guess you like

Origin blog.csdn.net/ly0724ok/article/details/122068413