Android上下文Context

本文详细解析了Android中Context的概念,包括其作为应用全局信息接口的角色、系统如何实现具体Context,以及不同类型的Context如Application Context和Activity Context。还讨论了Context在访问资源、启动组件以及在实际开发中的应用场景,如在Dialog开发中的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android的Context是一个经常用到的概念,由于它是一个抽象类所以更多时候我们见到或使用到的是它的子类,比如getApplicationContext(),getBaseContext(),getContext()。中文一般翻译成“上下文”,结合汉语中对上下文的解释不难理解Android环境中对Context的定义和重要性。Android应用是由一个个组件组成的(各个Activity,Service,View等),想要合理的沟通和运行这些组件就需要Context来作为“桥梁”。这篇文章就来好好总结下Android中Context相关的知识点。

1.概念

首先来看官方对Context的解释:

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.

这段话告诉我们这几点信息:
1.Context是应用环境的全局信息接口;
2.Context是抽象类不能直接使用,具体实现交给Android系统;
3.Context用来访问资源和类,启动activity,brocadcast和接受intent等。

下面先好好解释下这3点信息。

1.1 应用全局信息接口

上面提到Context是Android各个组件沟通桥梁,主要就是四大组件+资源。看下面一张图:
在这里插入图片描述

Activity类继承了ContextThemeWrapper,而Service继承了ContextWrapper,都间接继承了Context。ContextImpl是Context的具体实现,ContextWrapper是对ContextImpl的进一步包装(利用mBase对象,实际是一个Context对象)。ActivityThread类是Android应用框架的核心对象,它就在ContextImpl类中。有了这些认知我们可以更好的理解官方概念中的“应用全局信息接口”这句话。

1.2 Android系统实现具体Context

Android的具体Context其实有多种,getApplicationContext()方法得到的是一个APP全局的Context,在Fragment中getActivity()方法得到的又是一个Activity类型的Context,View中又通常采用getContext()来获取Context。

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

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

        Context context0 = getApplicationContext();
        Context context1 = getApplication();
        Context context2 = getBaseContext();
        Context context3 = this;
        Context context4 = new ContextWrapper(this);

        Log.d(TAG,">>>>>>> getApplicationContext = " + context0);
        Log.d(TAG,">>>>>>> getApplication = " + context1);
        Log.d(TAG,">>>>>>> getBaseContext = " + context2);
        Log.d(TAG,">>>>>>> activity.this = " + context3);
        Log.d(TAG,">>>>>>> new ContextWrapper(this) = " + context4);


    }
}

//打印
D/MainActivity: >>>>>>> getApplicationContext = android.app.Application@5ec6462
D/MainActivity: >>>>>>> getApplication = android.app.Application@5ec6462
D/MainActivity: >>>>>>> getBaseContext = androidx.appcompat.view.ContextThemeWrapper@208c9f3
D/MainActivity: >>>>>>> activity.this = com.zsf.androidadvanceddecode.MainActivity@22bd968
D/MainActivity: >>>>>>> new ContextWrapper(this) = android.content.ContextWrapper@3836b0

1.3 访问资源和类

这个点主要可以看ContextWrapper类,在这个类中保存了Theme资源和Resource资源。很多系统级服务都需要使用Context来调用,比如WiFi:

WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);

2.Application Context介绍

还是上面那张图,ContextImpl是Context抽象类的具体实现,Application类继承与ContextWrapper,Application又是一个APP的唯一实例(APP启动,Application创建,且在整个APP生命周期内都只有这一个Application实例),我们使用getApplicationContext()来获取一个全局性的Context。思考它是如何创建出来的?

上面提到APP核心框架类ActivityThread,它作为应用进程的主线程管理类,负责启动activity,广播和activity有关请求操作。

//frameworks/base/core/java/android/app/ActivityThread.java
    @Override
    public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                                             ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
                                             CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
                                             int procState, Bundle state, PersistableBundle persistentState,
                                             List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
                                             boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {

        updateProcessState(procState, false);

        ActivityClientRecord r = new ActivityClientRecord();
        r.token = token;
        r.ident = ident;
        r.intent = intent;
        r.referrer = referrer;
        r.voiceInteractor = voiceInteractor;
        r.activityInfo = info;
        r.compatInfo = compatInfo;
        r.state = state;
        r.persistentState = persistentState;
        r.pendingResults = pendingResults;
        r.pendingIntents = pendingNewIntents;
        r.startsNotResumed = notResumed;
        r.isForward = isForward;
        r.profilerInfo = profilerInfo;
        r.overrideConfig = overrideConfig;
        updatePendingConfiguration(curConfig);
        
        //发送Handler消息启动Activity
        sendMessage(H.LAUNCH_ACTIVITY, r);
    }

H是ActivityThread的内部类:

    private class H extends Handler {
        public static final int LAUNCH_ACTIVITY = 100;
        //...省略


        public void handleMessage(Message msg) {
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

                    //获的LoadedApk对象
                    r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo);
                    //继续点进去该方法
                    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                }
                break;

                //...省略
            }
        }

        //...省略


    }
    
    
    
    private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
        //...

        Activity a = performLaunchActivity(r, customIntent);
        
        //...
    }
    
    
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        //...
        //总算看到了有关Application的
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);
        
        //...
    }
///frameworks/base/core/java/android/app/LoadedApk.java

    public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) {
        //第一次启动APP,mApplication = null
        if (mApplication != null) {
            return mApplication;
        }

        //...

        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
        //创建Application
        app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);
        //将Application类型的对象app赋值给变量mOuterContext,它是一个ContextImpl对象
        appContext.setOuterContext(app);

        //...

        //将app赋值给成员变量mApplication,它是Application类型的对象
        mApplication = app;

        //...

    }

到这里我们已经离终点不远了,接下来我们继续看newApplication(cl, appClass, appContext)是如何创建Application的。

//frameworks/base/core/java/android/app/Instrumentation.java
    static public Application newApplication(Class<?> clazz, Context context) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        Application app = (Application) clazz.newInstance();
        app.attach(context);
        return app;
    }
    
    
    //frameworks/base/core/java/android/app/Application.java
    final void attach(Context context) {
        //ContextWrapper中实现该方法
        attachBaseContext(context);
        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
    }
    
    
    //frameworks/base/core/java/android/content/ContextWrapper.java
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        //base是ContextImpl,将它赋值给成员变量mBase
        mBase = base;
    }

ContextWrapper的成员变量mBase获取了ContextImpl,ComtextImpl又是Context的具体实现,Application又是继承了ContextWrappter。到这里一个APP成功创建了一个Application Context。

3.Activity Context

下面我们再看下Activity中Context是怎么来的。有了前面Application Context的经历,下面将仅记录关键代码。

//frameworks/base/core/java/android/app/ActivityThread.java
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        //...
        //创建Activity的ContextImpl
        ContextImpl appContext = createBaseContextForActivity(r);
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
            activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);

            //...
        } catch (Exception e) {
            //...
        }

        //...
        if (activity != null) {
            //...

            //赋值给ContextImpl的成员变量mOuterContext
            appContext.setOuterContext(activity);
            //传入appContext
            activity.attach(appContext, this, getInstrumentation(), r.token,
                    r.ident, app, r.intent, r.activityInfo, title, r.parent,
                    r.embeddedID, r.lastNonConfigurationInstances, config,
                    r.referrer, r.voiceInteractor, window, r.configCallback);
        }
        //...
    }

下面的分析参考Application Context的过程即可。

4. 其他有关Context的认识

1.实际开发中getApplication()方法一般用在Activity/Service中,而getApplicationContext()一般用在广播BroadcastReceiver中。上面的打印我们也可以看到这两个其实代表了同一个对象(对象地址一样)。
2.Dialog开发中,一般传递的是Activity的Context,因为Android要求Dialog不能独立存在,必须依附与Activity界面。
3.一个App进程Context数量=Activity数量+Service数量+1(Application);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值