Android系统源码分析--Context
Android是一个开源系统,至少说是大部分开源的,源代码的学习对于我们学习Android帮助非常大,可能很多人看看源码时感觉代码太多了,不知道从何开始,今天我就从基本的部分开始跟大家一起学习Android源码。
声明:本篇以及以后Android源码分析是基于Android-7.1.2_r11(7.1版本系统)源码进行分析。如果之后切换会进行声明。希望对照源码学习的要找对应版本进行查看。
在开始介绍Context前我们先看一张Android系统框架层的图:
从上面图可以看到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.名称)直接获取,然后进行操作。
类图
首先看一下类图关系:
讲解:
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】
1 | Context mBase; |
我们可以看到只有构造函数和attachBaseContext方法传入了mBase,那么从attachBaseContext方法中我们看到如果mBase存在又调用了该方法就会抛出异常,因此我们知道如果调用了该方法,那么构造函数不能传入这个值,我们看一下哪些地方调用了这个attachBaseContext方法,由代码可以看到Application、activity和service均调用了这个方法,首先我们来看Application中的代码:
【Application.java】
1 | /** |
Application中的attach方法中调用了attachBaseContext方法,参数context也是通过attach方法传入的,那么我们再跟踪这个attach方法:
是在Instrumentation类中调用的:
【Instrumentation.java】
1 | static public Application newApplication(Class<?> clazz, Context context) |
上面方法调用地方是:
【Instrumentation.java】
1 | public Application newApplication(ClassLoader cl, String className, Context context) |
从代码可以看到是在new Application时调用的,那么我们接着看哪里调用了这个方法:
【LoadedApk.java】
1 | public Application makeApplication(boolean forceDefaultAppClass, |
上面方法是在LoadedApk类中调用的,我们先不分析这个类,后续我们会详细讲这个过程,我们先分析上面这段代码,我们看到这里面通过调用ContextImpl.createAppContext方法来创建ContextImpl,然后将参数传入newApplication方法,因此我们看到上面的mBase就是ContextImpl,那么还有Activity和Service.我们先分析Service,因为从关系图可以看到Service和Application都是直接继承ContextWrapper,而Activity则是继承ContextThemeWrapper,ContextThemeWrapper继承ContextWrapper。
【Service.java】
1 | public final void attach( |
attachBaseContext方法是在Service中的attach方法中调用的,接着看attach方法的调用:
【ActivityThread.java】
1 | private void handleCreateService(CreateServiceData data) { |
在这里我们看到传入的context就是ContextImpl,从而得到验证,下面我们还看到service.onCreate方法,我们看到了先调用attach方法然后调用onCreate方法。
最后我们看一下Activity,从上面关系图我们看到,Activity不是直接继承ContextWrapper,而是继承的ContextThemeWrapper,ContextThemeWrapper继承ContextWrapper。从名字我们可以看到ContextThemeWrapper包含主题的信息,其实不难理解,四大组件只有Activity是带界面的,其他都是没有界面的,因此Activity需要主题信息来显示不同的界面效果。在ContextThemeWrapper中我们看到复写了attachBaseContext方法,方法中只有一行代码就是调用父类的attachBaseContext方法。如下所示:
【ContextThemeWrapper.java】
1 |
|
在Activity中只有一个方法中调用了该方法,看代码:
【Activity.java】
1 | final void attach(Context context, ActivityThread aThread, |
我们接着追踪attach方法,看代码:
【ActivitThread.java】
1 | private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { |
方法performLaunchActivity其实是启动Activity的方法,这里我们暂时不讲,后续我们会详细讲解,我们先理清楚Context,从上面代码我们可以看到此处传入的Context是通过createBaseContextForActivity方法创建的,那么我们看一下这个方法:
【ActivitThread.java】
1 | private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) { |
从上面代码我肯可以清楚的看到baseContext是appContext赋值的,而appContext就是ContextImpl,因此Activity中的Context也是ContextImpl。到现在我们已经搞清楚了ContextImpl、Context、ContextWrapper、ContextThemeWrapper以及Application、Service和Activity的关系,那么以后看源码我们就知道与Context相关的实现方法都在ContextImpl类中,如果需要看详细实现过程只需要去ContextImpl类中找到相应方法开始跟踪即可。
从下一章我们开始讲解四大组件的启动过程。
代码地址:
直接拉取导入开发工具(Intellij idea或者Android studio)
注
Android开发群:192508518
微信公众账号:Code-MX
注:本文原创,转载请注明出处,多谢。