正文
public static Class<?> TYPE = RefClass.load(ContextImpl.class, "android.app.ContextImpl");
这句才是实际的初始化入口。第二个参数指定反射的操作目标类为
android.app.ContextImpl
。这个是框架的硬性要求。
接下来几个都是对要反射的变量。分别对应实际的
ContextImpl
类内部的
mBasePackageName
、
mPackageInfo
、
mPackageManager
、
getReceiverRestrictedContext
成员和方法。
注意,这里只有声明的过程,没有赋值的过程。这个过程,便完成了传统的查找目标类内的变量域、方法要干的事情。从代码上看,相当的简洁直观。
下面这个表格,能更直观形象的表现它的优雅:
反射结构类型
声明
实际类型
实际声明
RefClass
mirror.android.app.ContextImp
Class
android.app.ContextImp
RefObject<String>
mBasePackageName
String
mBasePackageName
RefObject<Object>
mPackageInfo
LoadedApk
mPackageInfo
RefObject<PackageManager>
mPackageManager
PackageManager
mPackageManager
@MethodParams
({Context.class})
Params
(Context.class)
RefMethod<Context>
getReceiverRestrictedContext
Method
getReceiverRestrictedContext
除了形式上略有差异,两个类之间的结构上是保持一一对应的!
使用
接着,查找到这些变量域和方法后,当然是要用它们来修改内容,调用方法啦,怎么用呢:
ContextImpl.mBasePackageName.set(context, hostPkg);
Context receiverContext = ContextImpl.getReceiverRestrictedContext.call(context);
用起来是不是也相当直观?一行代码,就能看出要做什么事情。比起最开始提及的那种方式,这种方式简直清晰简洁得不要不要的,一鼓作气读下来不带停顿的。这样的代码几乎没有废话,每一行都有意义,信息密度杠杠的。
到这里就讲完了声明和使用这两个步骤。确实很简单吧?接下来再来看看实现。
实现分析
结构
首先看看这个框架的类图:
摆在中间的
RefClass
是最核心的类。
围绕在它周边的
RefBoolean
、
RefConstructor
、
RefDouble
、
RefFloat
、
RefInt
、
RefLong
、
RefMethod
、
RefObject
、
RefStaticInt
、
RefStaticMethod
、
RefStaticObject
则是用于声明和使用的反射结构的定义。从名字也能直观的看出该反射结构的类型信息,如构造方法、数据类型、是否静态等。
在右边角落的两个小家伙
MethodParams
、
MethodReflectParams
是用于定义方法参数类型的注解,方法相关的反射结构的定义会需要用到它。它们两个的差别在于,
MethodParams
接受的数据类型是
Class<?>
,而
MethodReflectParams
接受的数据类型是字符串,对应类型的全描述符,如
android.app.Context
,这个主要是服务于那些Android SDK没有暴露出来的,无法直接访问到的类。
运作
初始化
从上面的表格可以知道,
RefClass
是整个声明中最外层的结构。这整个结构要能运作,也需要从这里开始,逐层向里地初始化。上文也提到了,
RefClass.load(Class mappingClass, Class<?> realClass)
是初始化的入口。初始化的时机呢?我们知道,Java虚拟机在加载类的时候,会初始化静态变量,定义里的
TYPE = RefClass.laod(...)
就是在这个时候执行的。也就是说,当我们需要用到它的时候,它才会被加载,通过这种方式,框架具备了按需加载的特性,没有多余的代码。
入口知道了,我们来看看
RefClass.load(Class<?> mappingClass, Class<?> realClass)
内部的逻辑。
先不放源码,简单概括一下:
在
mappingClass
内部,查找需要初始化的反射结构(如
RefObject<String> mBasePackageName
)
实例化查到到的反射结构变量(即做了
RefObject<String> mmBasePackageName = new RefObject<String>(...)
)
查找,就需要限定条件范围。结合定义,可以知道,要查找的反射结构,具有以下特点:
静态成员
类型为
Ref*
查找的代码如下:
public static Class load (Class mappingClass, Class<?> realClass) {
Field[] fields = mappingClass.getDeclaredFields();
for