您的位置:首页 > 其它

[置顶] 源码阅读--应用上下文环境Context

2017-09-30 09:57 459 查看

Context上下文环境包括哪些

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.

提供应用环境的全局信息的接口,可以获取到应用自有的资源和class类,同时应用层级操作(启动activity,发送广播等)

看一下Context源码中的方法定义:上图罗列了部分方法定义getResources()、getDrawable()、getClassLoader()是获取到应用自有的资源和class类相关的方法,此外有startActivity()等方法进行组件级操作。

2.此外,还有一些对数据文件的操作:sp,文件,数据库;方法getSystemService()提供了获取系统服务的能力

总结一下,Context提供了以下应用上下文环境:

1.应用自有资源与代码

2.组件操作(组件启动,广播,Receiver注册等)

3.数据IO操作

4.系统服务获取

5.主线程关联

Context的结构设计采用了装饰者模式。Activity,Service和Application都直接或间接继承自ContextWrapper,这三个类很少对ContextWrapper方法进行重写(Activity处理较多),对而ContextWrapper把所有功能都委托给ContextImpl来实现,Context的基础功能基本上都在ContextImpl中实现。

资源管理与代码加载

资源管理

以getDrawable为例,看一下Context如何获取资源文件:

Context.java

public final Drawable getDrawable(@DrawableRes int id){
return getResources().getDrawable(id, getTheme());
}


ContextImpl.java



默认会调用LoadedApk的getResources方法获取Resources对象。

LoadedApk.java



ActivityThread.java



可以看出所有的Resources创建都汇集到ResourcesManager这个类来进行。ResourcesManager采用单例模式,也就是说同一进程下的Resources对象是由同一个ResourcesManager创建的。具体的资源管理会在后面分析。

代码加载

java类加载遵循双亲委托模型,android同样遵循该模型,只是在ClassLoader的继承结构上有差异。看一下ClassLoader的创建:

ContextImpl.java



LoadedApk.java



在createOrUpdateClassLoaderLocked方法中,调用了ApplicationLoader的getClassLoader方法:



可以看到这里ClassLoader是PathClassLoader对象。

看一下PathClassLoader类的注释,

Android uses this class for its system class loader and for its application class loader(s).

这个类加载器用于加载安卓系统类和应用程序类,这里的应用必须是已安装的。这也说明上面的ClassLoader对象是PathClassLoader对象。

更多ClassLoader信息参考:Android动态加载之ClassLoader详解

LoadedApk

从前面可以看出,资源和代码的管理都用到了LoadedApk这个类。

在ActivityThread类中,提供了获取LoadedApk对象的方法



LoadedApk.java

loaded描述了一个已加载的apk的状态。下图展示了LoadedApk的主要成员,包括apk位置,资源目录,数据目录等,最主要的是ApplicationInfo,可以看到主要成员的设置跟ApplicationInfo是相关的。







数据操作

安卓的数据存储包括SharedPrefereces,File,DataBase,网络等方式,Context提供了部分数据源API包括Sp,File,DataBase。

Sp

Sp数据以xml文件形式存储在data/data/<包名>/preferens目录下。Context提供getSharedPreferences方法返回SharedPreferencesImpl对象

File

Context提供openFileInput和openFileOutput用于处理文件这里的文件默认是位于data/data/<包名>/files目录下的。

sd卡目录可以通过Environment.getExternalStorageDirectory()获取。Context也提供了一些Api获取sd卡目录,也是通过Environment

Database

Context提供openOrCreateDatabase创建数据库,但数据库相关操作一般是使用SQLiteOpenHelper

系统服务

Context定义了一系列Service常量名,可以通过getSystemService(String name)获取对应服务。

Context创建

Context使用了装饰这模式,Application等Context子类对象其实是封装了ContxetImpl的实现,通过持有的mBase对象(ContextImpl)实现具体操作。那么封装类和mBase是在什么时候关联的?

Application的创建

在应用进程启动以后,应用通过ActivityThread的main方法开始执行,先会bindApplication与AMS交互,在回调处理中会触发handleBindApplication方法,Application对象在此时创建。

Context关联

handleBindApplication



这里调用了LoadedApk的makeApplication方法



继续调用Instrumentation的newApplication



attach方法中调用了attachBaseContext在这里进行了Context关联





ContextImpl创建

在LoadedApk的makeApplication方法中调用了ContextImpl.createAppContext工厂方法。

ContextImpl类提供了三个静态工厂方法创建ContextImpl对象



LoadedApk是ContextImpl类中mPackageInfo的类型,一个重要成员。makeApplication中传入的参数是当前LoadedApk对象。再看一下前面makeApplication的调用

Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;


这里的data.info就是一个LoadedApk对象,创建也是在handleBindApplication方法中。

data.info = getPackageInfoNoCheck(data.appInfo,data.compatInfo);


ActivityThread提供getPackageInfo方法创建LoadedApk对象
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: