首页 » Android » Android系统源码分析--Context

Android系统源码分析--Context

原文 http://blog.csdn.net/u013899706/article/details/77970574

2017-09-13 22:20:37阅读(220)

Android是一个开源系统,至少说是大部分开源的,源代码的学习对于我们学习Android帮助非常大,可能很多人看看源码时感觉代码太多了,不知道从何开始,今天我就从基本的部分开始跟大家一起学习Android源码。
声明:本篇以及以后Android源码分析是基于Android-7.1.2_r11(7.1版本系统)源码进行分析。如果之后切换会进行声明。希望对照源码学习的要找对应版本进行查看。

在开始介绍Context前我们先看一张Android系统框架层的图:

Android系统源码分析--Context

从上面图可以看到Android系统主要分为五层:应用层,应用框架层,Native库和运行环境,硬件抽象层和Linux内核层。本章不重点讲Android系统框架,只是开始给大家展示一下,有个了解,我们先从Framework层开始学习,首先学习Context,下面进入正题。

概述:

做Android开发的朋友在开发过程中时刻用到Context,那么Context到底是什么,到底是做什么的我们详细分析一下。源码中解释Context是一个面向应用全局信息的接口,那么我看看哪些信息与Context有关:

获取AssetManager:getAssets(); 获取Resources:getResources(); 获取PackageManager:getPackageManager(); 获取ContentResolver:getContentResolver(); 获取主线程Looper:getMainLooper(); 获取Application的Context:getApplicationContext(); 获取资源文件:getText,getString,getColor,getDrawable,getColorStateList; 设置主题,获取主题资源id:setTheme,getThemeResId; 获取样式属性TypedArray:obtainStyledAttributes(); 获取类加载器ClassLoader:getClassLoader(); 获取应用信息对象ApplicationInfo:getApplicationInfo(); 获取SharedPreferences:getSharedPreferences(); 打开文件FileInputStream:openFileInput(); 删除文件:deleteFile(); 获取文件File:getFileStreamPath(); 打开或者创建数据库:openOrCreateDatabase(); 移除或者删除数据库:moveDatabaseFrom(),deleteDatabase(); 启动Activity:startActivity(),startActivityAsUser(),startActivityForResult(),startActivities(); 注册、发送、注销广播:registerReceiver(),sendBroadcast(),sendOrderedBroadcast(),unregisterReceiver(); 启动、绑定、解除绑定、停止服务:startService(),bindService(),unbindService(),stopService(); 获取系统服务:getSystemService(); 检查权限(Android 6.0以上):checkPermission(); 根据应用名创建Context:createPackageContext(); 根据应用信息创建Context:createApplicationContext(); 获取显示信息对象Display:getDisplay();

主要的信息关联就是这些,还有一些不常用的或者废弃的没有再展示,有兴趣自己看看源码,官方解释很清晰。上面有个获取系统服务,我们下面把所有的系统服务列举一下(前面是服务,后面是获取服务的名称):

android.view.WindowManager–#WINDOW_SERVICE—————————–窗口管理 android.view.LayoutInflater–#LAYOUT_INFLATER_SERVICE——————-布局加载器 android.app.ActivityManager–#ACTIVITY_SERVICE————————–Activity管理器 android.os.PowerManager–#POWER_SERVICE———————————电源管理 android.app.AlarmManager–#ALARM_SERVICE——————————–提醒管理 android.app.NotificationManager–#NOTIFICATION_SERVICE——————通知管理 android.app.KeyguardManager–#KEYGUARD_SERVICE————————–键盘管理 android.location.LocationManager–#LOCATION_SERVICE———————定位管理 android.app.SearchManager–#SEARCH_SERVICE——————————搜索管理 android.hardware.SensorManager–#SENSOR_SERVICE————————-传感器管理 android.os.storage.StorageManager–#STORAGE_SERVICE———————存储管理 android.os.Vibrator–#VIBRATOR_SERVICE———————————-震动管理 android.net.ConnectivityManager–#CONNECTIVITY_SERVICE——————网络管理 android.net.wifi.WifiManager–#WIFI_SERVICE—————————–Wifi管理 android.media.AudioManager–#AUDIO_SERVICE——————————音频管理 android.media.MediaRouter–#MEDIA_ROUTER_SERVICE————————媒体路由器 android.telephony.TelephonyManager–#TELEPHONY_SERVICE——————电话管理 android.telephony.SubscriptionManager–#TELEPHONY_SUBSCRIPTION_SERVICE–双卡信息管理 android.telephony.CarrierConfigManager–#CARRIER_CONFIG_SERVICE———电话配置信息管理 android.view.inputmethod.InputMethodManager–#INPUT_METHOD_SERVICE——输入法管理 android.app.UiModeManager–#UI_MODE_SERVICE—————————–UI模式管理 android.app.DownloadManager–#DOWNLOAD_SERVICE————————–下载管理 android.os.BatteryManager–#BATTERY_SERVICE—————————–电池管理 android.app.job.JobScheduler–#JOB_SCHEDULER_SERVICE——————–任务执行者 android.app.usage.NetworkStatsManager–#NETWORK_STATS_SERVICE———–网络状态管理 android.os.HardwarePropertiesManager–#HARDWARE_PROPERTIES_SERVICE——硬件属性管理

上面这些服务,你可以通过Context.getSystemService(Context.名称)直接获取,然后进行操作。

类图

首先看一下类图关系:

Android系统源码分析--Context

讲解:

1.ContextImpl、ContextWrapper与Context的关系

Context是一个静态类,ContextImpl和ContextWrapper都继承了Context,也就是都实现了Context的静态方法,但是,从代码中我们看到ContextImpl是Context静态方法的详细实现类,而ContextWrapper是调用了mBase对应的方法,而mBase是Context,从代码跟踪看mBase其实就是ContextImpl,因此ContextWrapper最终是调用ContextImpl中的实现方法。也就是说我们调用的Context中的任何方法都是在ContextImpl中处理的,因此我们在跟踪代码时只需要去ContextImpl中查看对应方法处理就好了。上面只是介绍,下面我们根据具体代码来分析一下到底怎么实现的。

从ContextWrapper代码中我们可以看到(不贴全部代码了),只有构造函数、attachBaseContext方法以及getBaseContext方法不是复写方法,其他方方法均为复写方法:

【ContextWrapper.java】

    Context mBase;
    public ContextWrapper(Context base) {
        mBase = base;
    }
    /**
     * Set the base context for this ContextWrapper.  All calls will then be
     * delegated to the base context.  Throws
     * IllegalStateException if a base context has already been set.
     * 
     * @param base The new base context for this wrapper.
     */
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }
    /**
     * @return the base context as set by the constructor or setBaseContext
     */
    public Context getBaseContext() {
        return mBase;
    }

我们可以看到只有构造函数和attachBaseContext方法传入了mBase,那么从attachBaseContext方法中我们看到如果mBase存在又调用了该方法就会抛出异常,因此我们知道如果调用了该方法,那么构造函数不能传入这个值,我们看一下哪些地方调用了这个attachBaseContext方法,由代码可以看到Application、activity和service均调用了这个方法,首先我们来看Application中的代码:

【Application.java】

    /**
     * @hide
     */
    /* package */ final void attach(Context context) {
        attachBaseContext(context);
        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
    }

Application中的attach方法中调用了attachBaseContext方法,参数context也是通过attach方法传入的,那么我们再跟踪这个attach方法:

是在Instrumentation类中调用的:

【Instrumentation.java】

    static public Application newApplication(Class<?> clazz, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        Application app = (Application)clazz.newInstance();
        app.attach(context);
        return app;
    }

上面方法调用地方是:

【Instrumentation.java】

    public Application newApplication(ClassLoader cl, String className, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        return newApplication(cl.loadClass(className), context);
    }

从代码可以看到是在new Application时调用的,那么我们接着看哪里调用了这个方法:

【LoadedApk.java】

public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        ...
        try {
            ...
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            appContext.setOuterContext(app);
        } catch (Exception e) {
            ...
        }
        ...
        return app;
    }

上面方法是在LoadedApk类中调用的,我们先不分析这个类,后续我们会详细讲这个过程,我们先分析上面这段代码,我们看到这里面通过调用ContextImpl.createAppContext方法来创建ContextImpl,然后将参数传入newApplication方法,因此我们看到上面的mBase就是ContextImpl,那么还有Activity和Service.我们先分析Service,因为从关系图可以看到Service和Application都是直接继承ContextWrapper,而Activity则是继承ContextThemeWrapper,ContextThemeWrapper继承ContextWrapper。

【Service.java】

public final void attach(
            Context context,
            ActivityThread thread, String className, IBinder token,
            Application application, Object activityManager) {
        attachBaseContext(context);
        ...
    }

attachBaseContext方法是在Service中的attach方法中调用的,接着看attach方法的调用:

【ActivityThread.java】

private void handleCreateService(CreateServiceData data) {
        ...
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManagerNative.getDefault());
            service.onCreate();
         ...
    }

在这里我们看到传入的context就是ContextImpl,从而得到验证,下面我们还看到service.onCreate方法,我们看到了先调用attach方法然后调用onCreate方法。

最后我们看一下Activity,从上面关系图我们看到,Activity不是直接继承ContextWrapper,而是继承的ContextThemeWrapper,ContextThemeWrapper继承ContextWrapper。从名字我们可以看到ContextThemeWrapper包含主题的信息,其实不难理解,四大组件只有Activity是带界面的,其他都是没有界面的,因此Activity需要主题信息来显示不同的界面效果。在ContextThemeWrapper中我们看到复写了attachBaseContext方法,方法中只有一行代码就是调用父类的attachBaseContext方法。如下所示:

【ContextThemeWrapper.java】

    @Override
    protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(newBase);
    }

在Activity中只有一个方法中调用了该方法,看代码:

【Activity.java】

final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window) {
        attachBaseContext(context);
        ...
    }

我们接着追踪attach方法,看代码:

【ActivitThread.java】

 private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
       ...
            if (activity != null) {
                Context appContext = createBaseContextForActivity(r, activity);
                ...
                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);
                ...
            }
            ...
        return activity;
    }

方法performLaunchActivity其实是启动Activity的方法,这里我们暂时不讲,后续我们会详细讲解,我们先理清楚Context,从上面代码我们可以看到此处传入的Context是通过createBaseContextForActivity方法创建的,那么我们看一下这个方法:

【ActivitThread.java】

private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
        ...
        ContextImpl appContext = ContextImpl.createActivityContext(
                this, r.packageInfo, r.token, displayId, r.overrideConfig);
        appContext.setOuterContext(activity);
        Context baseContext = appContext;
        ...
        return baseContext;
    }

从上面代码我肯可以清楚的看到baseContext是appContext赋值的,而appContext就是ContextImpl,因此Activity中的Context也是ContextImpl。到现在我们已经搞清楚了ContextImpl、Context、ContextWrapper、ContextThemeWrapper以及Application、Service和Activity的关系,那么以后看源码我们就知道与Context相关的实现方法都在ContextImpl类中,如果需要看详细实现过程只需要去ContextImpl类中找到相应方法开始跟踪即可。

从下一章我们开始讲解四大组件的启动过程。

首发地址:http://www.codemx.cn

Android开发群:192508518

微信公众账号:Code-MX

注:本文原创,转载请注明出处,多谢。

最新发布

CentOS专题

关于本站

5ibc.net旗下博客站精品博文小部分原创、大部分从互联网收集整理。尊重作者版权、传播精品博文,让更多编程爱好者知晓!

小提示

按 Ctrl+D 键,
把本文加入收藏夹