Android系统源码分析--Context

栏目: 编程工具 · 发布时间: 7年前

内容简介:Android系统源码分析--Context

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类中找到相应方法开始跟踪即可。

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

Android开发群:192508518

微信公众账号:Code-MX

Android系统源码分析--Context

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

纯属好玩

Android系统源码分析--Context

扫码打赏,多少你说算

Android系统源码分析--Context
Android系统源码分析--Context

打开 支付宝 扫一扫,即可进行扫码打赏哦


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

设计方法卡牌

设计方法卡牌

罗莎 等 / 电子工业出版社 / 2017-7 / 79.00

本套设计素材提供了54种设计方法,以卡牌的形式展示给读者,每张卡牌包括该设计方法的基本描述、目的、时间成本、工具渠道、使用阶段、操作步骤及其归类属性等信息。在做设计时,可以根据自己的需求进行卡牌的选择和组合,让设计工作更有灵活性和趣味性。同时,依据设计产品属性的不同,卡牌提供了选择设计方法的推荐模板、方法组合模板、产品阶段划分模板,给初学者在做设计时提供一定的理论依据,帮助读者启发设计灵感,剖析设......一起来看看 《设计方法卡牌》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

MD5 加密
MD5 加密

MD5 加密工具

html转js在线工具
html转js在线工具

html转js在线工具