Context是什么?
中文翻译为:上下文。
一个Activity就是一个Context,一个Service也是一个Context,Application也是一个Context。
Context能用来干什么?
启动界面、发送广播、获取资源等。
走进Context的世界
Context的关系图
Context
源码地址:
ContextImpl
源码地址:
ContextWrapper
源码地址:
ContextThemeWrapper
源码地址:
Application
Service
Activity
Context是怎么创建的?又是在哪创建的?
知识前提:
Android系统的启动流程(基于Android5.1.1系统源码)
大图链接:https://www.processon.com/view/link/5fd4b993e401fd06ddbe94b9
创建流程:
将ApplicationThread Binder注册到AMS中。
用于切换线程,处理AMS发送过来的消息。
Application 的 Context
Service 的 Context
划重点
静态注册的广播 和 动态注册的广播 最终在
onReceive(Context context, Intent intent)
方法里面的Context的不一样
Activity 的 Context
Android9.0之前
在mH里面定义了LAUNCH_ACTIVITY,执行handleLaunchActivity(r, null);
Android9.0 及之后
源码地址:
Activity生命周期相关的方法都直接走 EXECUTE_TRANSACTION 分支处理
ActivityLifecycleItem
ClientTransactionItem子类
ActivityLifeCycleItem子类
LauncherActivityItem实现
ContentProvider 的 Context
Broadcast Receiver 的 Context
广播是一个抽象类,没有继承ContextWrapper,也没有跟Context的成员变量。
如果广播是动态注册的话,onReceived方法里面参数context,就是注册时候的context。
如果是静态注册的话,是以Application Context 为Base的ContextWrapper
总结一下
Context类本身是一个抽象类,其有两个具体的实现类:ContextImpl 和 ContextWrapper。
ContextWrapper类 ,本身不实现具体操作,主要职责是转发和包装。其内部维护一个Context变量mBase,具体实现由该Context完成,该变量由attachBaseContext方法赋值。
ContextThemeWrapper类继承至ContextWrapper,添加了一些与主题相关的操作。
Application、Service 继承于 ContextWrapper。Activity 继承于 ContextThemeWrapper。
ContextImpl类 为 Context类 的具体实现类。
最后来看一下,Android中的四大组件中的各种Context的关系
1.首先创建一个最简单的Android工程,创建一个资源布局文件activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:onClick="test1"
android:text="比较 getApplicationContext() 与 getApplication() 区别" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:onClick="test2"
android:text="查看ContentProvider的Context" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:onClick="test3"
android:text="查看静态注册广播的Context" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:onClick="test4"
android:text="查看动态注册广播的Context" />
</LinearLayout>
界面如下
2.在MainActivity中创建几个方法
import android.app.Activity;
import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import com.zct.context.receiver.DynamicRegisterReceiver;
public class MainActivity extends Activity {
private BroadcastReceiver mDynamicReceiver = new DynamicRegisterReceiver();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//动态注册广播
registerReceiver();
}
/**
* 验证getApplication() 与 getApplicationContext() 区别
*
* @param view
*/
public void test1(View view) {
Application application = getApplication();
Context applicationContext = getApplicationContext();
Log.i(Constants.TAG, "test1 \n application = " + application + " , \n applicationContext = " + applicationContext);
}
/**
* 查看ContextProvider 的 Context 对象
*
* @param view
*/
public void test2(View view) {
Uri boyUri = Uri.parse("content://com.zct.context.MyContentProvider/test1");
ContentValues contentValues = new ContentValues();
Cursor boyCursor = getContentResolver().query(boyUri, new String[]{"_id", "name"}, null, null, null);
}
/**
* 查看静态注册的广播接受者的 Context
*
* @param view
*/
public void test3(View view) {
Log.i(Constants.TAG, "\n MainActivity test3 = " + this + "");
Intent intent = new Intent();
intent.setAction("static_register_broadcast_receiver");
intent.setPackage(getPackageName());//
sendBroadcast(intent);
}
/**
* 查看动态注册的广播接受者的 Context
*
* @param view
*/
public void test4(View view) {
Log.i(Constants.TAG, "\n MainActivity test4 = " + this + "");
Intent intent = new Intent();
intent.setAction(Constants.DYNAMIC_ACTION);
sendBroadcast(intent);
}
private void registerReceiver() {
IntentFilter dynamicFilter = new IntentFilter();
dynamicFilter.addAction(Constants.DYNAMIC_ACTION);
registerReceiver(mDynamicReceiver,dynamicFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
unRegisterReceiver();
}
private void unRegisterReceiver() {
unregisterReceiver(mDynamicReceiver);
}
}
3.DynamicRegisterReceiver 代码如下
public class DynamicRegisterReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.i(Constants.TAG, "DynamicRegisterReceiver onReceive context = " + context);
}
}
4.StaticRegisterReceiver 代码如下
public class StaticRegisterReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//3980
Log.i(Constants.TAG, "StaticRegisterReceiver onReceive context = " + context);
}
}
两个同样都是广播,只是StaticRegisterReceiver在AndroidManifest.xml中静态注册,DynamicRegisterReceiver在MainActivity中动态注册。
5. MyContentProvider 为内容提供者,这里没有实现具体的方法,仅为了验证其中Context的关系。
public class MyContentProvider extends ContentProvider {
@Override
public boolean onCreate() {
return false;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] strings, @Nullable String s, @Nullable String[] strings1, @Nullable String s1) {
Context context = getContext();
Context applicationContext = getContext().getApplicationContext();
Log.i(Constants.TAG,"ContentProvider \n context = "+context+" , \n applicationContext = "+applicationContext);
return null;
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
return null;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String s, @Nullable String[] strings) {
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String s, @Nullable String[] strings) {
return 0;
}
}
6.最后看一下AndroidManifest.xml的代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.zct.context">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="com.zct.context.MyContentProvider"
android:authorities="com.zct.context.MyContentProvider"
android:exported="true" />
<receiver android:name=".receiver.StaticRegisterReceiver">
<intent-filter>
<action android:name="static_register_broadcast_receiver" />
</intent-filter>
</receiver>
</application>
</manifest>
激动人心的时刻到了,我们点击不同的按钮,来查看结果。
1. 比较 getApplicationContext() 与 getApplication() 区别
/**
* 验证getApplication() 与 getApplicationContext() 区别
*
* @param view
*/
public void test1(View view) {
Application application = getApplication();
Context applicationContext = getApplicationContext();
Log.i(Constants.TAG, "test1 \n application = " + application + " , \n applicationContext = " + applicationContext);
}
从打印结果可以看出 getApplication 与 getApplicationContext 方法返回的是相同的地址。区别在于getApplication仅在Activity中可以获取的到,返回的Application本身的实例对象。
2.
/**
* 查看ContextProvider 的 Context 对象
*
* @param view
*/
public void test2(View view) {
Uri boyUri = Uri.parse("content://com.zct.context.MyContentProvider/test1");
ContentValues contentValues = new ContentValues();
Cursor boyCursor = getContentResolver().query(boyUri, new String[]{"_id", "name"}, null, null, null);
}
MyContentProvider
public Cursor query(@NonNull Uri uri, @Nullable String[] strings, @Nullable String s, @Nullable String[] strings1, @Nullable String s1) {
Context context = getContext();
Context applicationContext = getContext().getApplicationContext();
Log.i(Constants.TAG,"ContentProvider \n context = "+context+" , \n applicationContext = "+applicationContext);
return null;
}
从执行结果可以看出,ContentProvider中的Context就是Application的Context。
3.查看静态注册广播的Context
/**
* 查看静态注册的广播接受者的 Context
*
* @param view
*/
public void test3(View view) {
Log.i(Constants.TAG, "\n MainActivity test3 = " + this + "");
Intent intent = new Intent();
intent.setAction("static_register_broadcast_receiver");
intent.setPackage(getPackageName());//
sendBroadcast(intent);
}
StaticRegisterReceiver.java
public class StaticRegisterReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//3980
Log.i(Constants.TAG, "StaticRegisterReceiver onReceive context = " + context);
}
}
从打印看到一个很奇怪的东西。ReceiverRestrictedContext是个什么鬼???
要想了解它是个什么东西,我们就翻一下他的源码。
原来它是Context的一个包装类,里面会拦截掉一些原有的方法,以保证某些方法在Receiver中不会被调用。
要想知道mBase具体是什么,这里断点跟一下。
可以得到结论,静态注册的广播,系统会为将Application的Context用ReceiverRestrictedContext进行一层包装,再返回给onReceiver方法。
4.查看动态注册广播的Context
/**
* 查看动态注册的广播接受者的 Context
*
* @param view
*/
public void test4(View view) {
Log.i(Constants.TAG, "\n MainActivity test4 = " + this + "");
Intent intent = new Intent();
intent.setAction(Constants.DYNAMIC_ACTION);
sendBroadcast(intent);
}
DynamicRegisterReceiver
public class DynamicRegisterReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.i(Constants.TAG, "DynamicRegisterReceiver onReceive context = " + context);
}
}
动态注册的广播与静态注册的广播就不一样了。其onReceiver方法中的Context就是注册这个广播时候的Context,由于我们在Activity中注册的,所以这里就是我们的MainActivity。
上面是本人学习研究的时候记录的,如果有不对的理解,请麻烦指出。互相学习,谢谢。