Detailed explanation of Android Context (full analysis)

Our most commonly used Activity, Service, and Application are all subclasses of Context. So it is very necessary to know the specific implementation of Context.
The following is the architecture diagram of Context:
insert image description here
Context itself is an abstract class. His implementation class is ContextImpl. And ContextWrapper is a wrapper class (decoration design pattern). When we use the IDE to view the Context inheritance relationship, we cannot directly see the ContextImpl class. By this method, the programmer cannot directly see the ContextImpl class, but only the ContextWrapper class. But if we really want to understand the principle of Context, ContextImpl is the most important, and ContextWrapper is just a shell.

We are very familiar with the subclasses of ContextWrapper, Application, Service, ContextThemeWrapper. Needless to say about the first two, we don’t need to care too much about ContextThemeWrapper, we can take a look when necessary, it is related to the theme, and its subclass Activity does not need to be said. So in fact the core class is the ContextImpl class.

The Context class is an abstract class with almost 5,000 lines, and almost all of them are abstract methods that have not been implemented, and almost 4,000 lines are comments. The real content may be less than 1000 lines. So the Context class is almost an interface specification document. And ContextImpl is only more than 2700 lines. And many of them are get methods. The ContextImpl class inherits the abstract class Context and implements all abstract methods, and also implements many get, create, and check methods. Even so, it only has 2,700 lines of code. To understand Context, the core is in these 2700 lines of code (many of which are get methods), and there is also the documentation class Context.

In these 2700 lines of code, the most important thing is ActivityThread mMainThread; this global variable. He is used the most.
The most commonly seen getApplicationContext, startActivity, getMainLooper are all implemented here, and the implementation method is very simple. These are all packaged by ActivityThread, and the specific content depends on the ActivityThread class. It will not be expanded here, and an article will be written to discuss it. Most of them are used and broadcasted. If you need to study broadcasting, you can take a look.

    @Override
    public Looper getMainLooper() {
    
    
        return mMainThread.getLooper();
    }

    @Override
    public Context getApplicationContext() {
    
    
        return (mPackageInfo != null) ?
                mPackageInfo.getApplication() : mMainThread.getApplication();
    }
    
    @Override
    public void startActivity(Intent intent, Bundle options) {
    
    
        warnIfCallingFromSystemProcess();

        mMainThread.getInstrumentation().execStartActivity(
                getOuterContext(), mMainThread.getApplicationThread(), null,
                (Activity) null, intent, -1, options);
    }
    
    //差不多有10个类似方法
    @Override
    public void sendBroadcast(Intent intent, String receiverPermission, int appOp) {
    
    

            ActivityManager.getService().broadcastIntent(
                    mMainThread.getApplicationThread(), intent, resolvedType, null,
                    Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false,
                    getUserId());

    }

The second most important variable is the LoadedApk mPackageInfo variable, because it is cited the second most times, either to obtain some content through mPackageInfo, or to make judgments through it. Of course, these functions are also encapsulated by the LoadedApk class. You can know what he does through his name. This class can manage the running .apk files. A detailed description of this class could also be written as a separate article.

  @Override
    public Context getApplicationContext() {
    
    
        return (mPackageInfo != null) ?
                mPackageInfo.getApplication() : mMainThread.getApplication();
    }
    @Override
    public String getPackageName() {
    
    
        if (mPackageInfo != null) {
    
    
            return mPackageInfo.getPackageName();
        }
        // No mPackageInfo means this is a Context for the system itself,
        // and this here is its name.
        return "android";
    }
    @Override
    public ApplicationInfo getApplicationInfo() {
    
    
        if (mPackageInfo != null) {
    
    
            return mPackageInfo.getApplicationInfo();
        }
        throw new RuntimeException("Not supported in system context");
    }

    @Override
    public String getPackageResourcePath() {
    
    
        if (mPackageInfo != null) {
    
    
            return mPackageInfo.getResDir();
        }
        throw new RuntimeException("Not supported in system context");
    }
    
//差不多有10个
void sendOrderedBroadcast() {
    
    
           多处用mPackageInfo做判断
        }
  
  
    }

The difference between getContext(), getBaseContxet(), getApplication, getApplicationContext

These are very confusing for novices. In the end there is a difference?

Let me talk about the difference between getApplication and getApplicationContext first. If you print these two methods in the Activity, the object memory address is the same, that is, the objects obtained by these two methods are the same? In fact, the two retrieved objects are the same object. The only thing that can be used is different. The getApplication method is only available for Activity and Service. If you want to get Application in other places, you can only get it through getApplicationContext.
Here is another question, why getApplication and getApplicationContext get the same object?
For reasons of space. You can read this article, as long as you know that the objects obtained by these two methods are the same.
That is, they are almost equivalent. The only difference is whether there is a getApplication method for you to use.
https://www.cnblogs.com/mingfeng002/p/11995177.html


What is the difference between getContext(), getBaseContxet(), and getApplicationContext ?
First of all, Activity, Service and Application all have getBaseContxet() and getApplicationContext(). But there is no getContext method. In Fragment, there is only getContext method. The object obtained by Fragment's getContext method is its host object, which is Activity. If you look at the source code of getContext, after a series of packaging, what you actually get is the Activity object where it is located.

public class MainActivity extends AppCompatActivity 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Log.d("MainActivity", "getBaseContext():" + getBaseContext());//ContextImpl对象
        Log.d("MainActivity", "getApplicationContext():" + getApplicationContext());
        Log.d("MainActivity", "getApplication():" + getApplication());
        Log.d("MainActivity", "this:" + this);//Activity对象
    }


public class BlankFragment extends Fragment {
    
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        Log.d("BlankFragment", "getContext():" + getContext());
    }
}

getBaseContext():androidx.appcompat.view.ContextThemeWrapper@72a2522
getApplicationContext():android.app.Application@e8e5bb3
getApplication():android.app.Application@e8e5bb3
this:com.example.viewpagerdemo.MainActivity@b0be2f
getContext():com.example.viewpagerdemo.MainActivity@b0be2f

In the output, we can see that the this of getContext and MainActivity are the same object, and the objects obtained by getApplicationContext and getApplication are also the same object, which is also in line with our proof.

Application usage

First of all, Application is a global singleton. So it is redundant to implement the singleton by yourself, just get it through the above getApplication or getApplicationContext.
Calling the context method in the application needs to be done after attachBaseContext. Because the assignment of context is done in attachBaseContext.
For example, calling the Context method in the constructor will crash because it has not been assigned yet.
It is possible to call Context in the onCreate method, but the limit operation is in the attachBaseContext method.

public class MyApplication extends Application {
    
    
	
	@Override
	protected void attachBaseContext(Context base) {
    
    
		// 在这里调用Context的方法会崩溃
		super.attachBaseContext(base);
		// 在这里可以正常调用Context的方法
	}
	
}

Guess you like

Origin blog.csdn.net/ScottePerk/article/details/122613765