• Application/Activity/Service作为Context的区别

    ContextImpl的创建
    服务器君一共花费 83.747 ms 进行了 2 次数据库查询,努力地为您提供了这个页面。
    广告很萌的

    Context在android中的作用不言而喻,当我们访问当前应用的资源,启动一个新的activity的时候都需要提供Context,而这个Context到底是什么呢,这个问题好像很好回答又好像难以说清楚。从字面意思,Context的意思是“上下文”,或者也可以叫做环境、场景等,尽管如此,还是有点抽象。

    从类的继承来说,Context作为一个抽象的基类,它的实现子类有三种:Application、Activity和Service(估计这么说,暂时不管ContextWrapper等类),那么这三种有没有区别呢?为什么通过任意的Context访问资源都得到的是同一套资源呢?getApplication和getApplicationContext有什么区别呢?应用中到底有多少个Context呢?

    Context是一个抽象基类,我们通过它访问当前包的资源(getResources、getAssets)和启动其他组件(Activity、Service、Broadcast)以及得到各种服务(getSystemService),当然,通过Context能得到的不仅仅只有上述这些内容。对Context的理解可以来说:Context提供了一个应用的运行环境,在Context的大环境里,应用才可以访问资源,才能完成和其他组件、服务的交互,Context定义了一套基本的功能接口,我们可以理解为一套规范,而Activity和Service是实现这套规范的子类,这么说也许并不准确,因为这套规范实际是被ContextImpl类统一实现的,Activity和Service只是继承并有选择性地重写了某些规范的实现。

    Application、Activity和Service作为Context的区别

    首先,它们都间接继承了Context,这是它们的相同点。

    不同点,可以从几个方面来说:首先看它们的继承关系:

    通过对比可以清晰地发现,Service和Application的类继承关系比较像,而Activity还多了一层继承ContextThemeWrapper,这是因为Activity有主题的概念,而Service是没有界面的服务,Application更是一个抽象的东西,它也是通过Activity类呈现的。

    下面来看一下三者在Context方面的区别。

    上文已经指出,Context的真正实现都在ContextImpl中,也就是说Context的大部分方法调用都会转到ContextImpl中,而三者的创建均在ActivityThread中完成。Activity启动的核心过程是在ActivityThread中完成的,Application和Service的创建也是在ActivityThread中完成的。下面我们看下三者在创建时是怎么和ContextImpl相关联的。

    Activity对象中ContextImpl的创建

    代码为ActivityThread中的performLaunchActivity方法:

    if (activity != null) {  
        Context appContext = createBaseContextForActivity(r, activity);  
        /** 
         *  createBaseContextForActivity中创建ContextImpl的代码 
         *  ContextImpl appContext = new ContextImpl(); 
         *  appContext.init(r.packageInfo, r.token, this); 
         *  appContext.setOuterContext(activity); 
         */  
        CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());  
        Configuration config = new Configuration(mCompatConfiguration);  
        if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "  
                + r.activityInfo.name + " with config " + config);  
        activity.attach(appContext, this, getInstrumentation(), r.token,  
                r.ident, app, r.intent, r.activityInfo, title, r.parent,  
                r.embeddedID, r.lastNonConfigurationInstances, config);  
      
        if (customIntent != null) {  
            activity.mIntent = customIntent;  
        }  
        ...  
    } 
    

    可以看出,Activity在创建的时候会new一个ContextImpl对象并在attach方法中关联它,需要注意的是,创建Activity使用的数据结构是ActivityClientRecord。

    Application对象中ContextImpl的创建

    代码在ActivityThread中的handleBindApplication方法中,此方法内部调用了makeApplication方法

    public Application makeApplication(boolean forceDefaultAppClass,  
            Instrumentation instrumentation) {  
        if (mApplication != null) {  
            return mApplication;  
        }  
      
        Application app = null;  
      
        String appClass = mApplicationInfo.className;  
        if (forceDefaultAppClass || (appClass == null)) {  
            appClass = "android.app.Application";  
        }  
      
        try {  
            java.lang.ClassLoader cl = getClassLoader();  
            ContextImpl appContext = new ContextImpl();  
            appContext.init(this, null, mActivityThread);  
            app = mActivityThread.mInstrumentation.newApplication(  
                    cl, appClass, appContext);  
            appContext.setOuterContext(app);  
        } catch (Exception e) {  
            if (!mActivityThread.mInstrumentation.onException(app, e)) {  
                throw new RuntimeException(  
                    "Unable to instantiate application " + appClass  
                    + ": " + e.toString(), e);  
            }  
        }  
        ...  
    } 
    

    看代码发现和Activity中ContextImpl的创建是相同的。

    Service对象中ContextImpl的创建

    通过查看代码发现和Activity、Application是一致的。分析到这里,那么三者的Context有什么区别呢?没有区别吗?

    尽管如此,有一些细节是确定的:Dialog的使用需要Activity,在桌面上我们采用Application的Context无法弹出对话框,同时在桌面上想启动新的activity,我们需要为intent设置FLAG_ACTIVITY_NEW_TASK标志,否则无法启动activity,这一切都说明,起码Application的Context和Activity的Context还是有区别的,当然这也可能不是Context的区别,因为在桌面上,我们的应用没有界面,这意味着我们能干的事情可能受到了限制,事情的细节目前我还没有搞的很清楚。

更多 推荐条目

Welcome to NowaMagic Academy!

现代魔法 推荐于 2013-02-27 10:23   

本章最新发布
随机专题
  1. [JavaScript程序设计] Web实时通信技术名词解析 5 个条目
  2. [Python程序设计] urls.py设置技巧 8 个条目
  3. [Python程序设计] Django模板系统 11 个条目
  4. [运维管理] 路由器与交换机 4 个条目
  5. [移动开发] Android 网络通信框架Volley 1 个条目
  6. [移动开发] Android加载器Loaders 5 个条目
  7. [移动开发] Content Provider内容提供者 3 个条目
  8. [Linux操作系统] 基本 Linux Shell 命令 2 个条目
  9. [JavaScript程序设计] 关于HTTP Keep-Alive 6 个条目
  10. [移动开发] 使用support-v7 ActionBar前的那些坑 3 个条目
  11. [移动开发] ListView 使用相关问题集 1 个条目
  12. [智力开发与知识管理] 整体性学习步骤 9 个条目
窗口 -- [协会]