您的位置:首页

xUtils3源码分析(一):view的绑定

2016-07-14 11:21 302 查看

概述

xUtils3是国人开发的一款功能丰富的Android快速开发框架,值得研究下。
zip包下载:[ZIP]
xutils主要分以下几个模块

视图绑定模块

网络请求模块

数据库模块

图片加载模块

我们将逐一透过源码分析,本文分析视图绑定模块,包含
View
的注入和
View
事件的注入。
我们将项目导入AndroidStudio,项目结构:



项目结构

xutils为项目源码,sample为使用方法举例。
我们通过分析sample这个示例项目来分析xutils的内部细节。
首先我们看看
MyApplication
这个类:



MyApplication

xUtils3在初始化的时候必须在自定义的
Application
中来完成初始化,代码为
x.Ext.init(this);
,首先就涉及到了这个
x
类,我们打开看看:

/**
* Created by wyouflf on 15/6/10.
* 任务控制中心, http, image, db, view注入等接口的入口.
* 需要在在application的onCreate中初始化: x.Ext.init(this);
*/
public final class x {
...省略代码
}

通过类注释我们可以看到
x
类是所有模块的入口。
那我们看看
x.Ext
这个内部类:



x.Ext

该类提供了一系列的静态成员变量,和对应的
set
方法,对应了
xutils
提供的几个功能模块。
看看
init
方法:



x.Ext.init(Application app)方法

很明显将
Application
绑定到
app
上,方便全局调用。
接下来我们分模块说明:

View注入

我们找到一个
BaseActivity
:



BaseActivity

Activity
onCreate
方法中,调用:
x.view().inject(this)
来完成视图注解框架的初始化。
看看
view()
方法做了什么:



x.view()

该方法是用来进行
Ext.viewInjector
的初始化的,那么我们到
ViewInjectorImpl
看看
ViewInjectorImpl.registerInstance();
是如何初始化的:



ViewInjectorImpl.registerInstance()

非常清楚,一个单例模式,而
ViewInjectorImpl
其实实现了
ViewInjector
接口:



ViewInjectorImpl实现了ViewInjector接口

看看
ViewInjector
接口:



ViewInjector

该接口的说明很明了,就是可以不同对象类型进行视图注入,如
View
,
Avtivity
,以及
ViewHolder
,
fragment
,以满足各个场景的使用。
那我们进入到具体的
Activity
进行分析吧:



MainActivity

可以看到
MainActivity
继承了
BaseActivity
,另外我们可以很明显的看到两种注解:
@ContentView(id)
@ViewInject(id)
,我们先看看
ContentView
注解的源码:



ContentView

@Target(ElementType.TYPE)
说明了该注解作用于类,接口或者枚举类型上。
@Retention(RetentionPolicy.RUNTIME)
说明该注解会一直保留到JVM运行时。
int Value()
说明可以注解参数的类型为
int
类型;
那么
@ContentView(R.layout.activity_main)
放入的就是布局
activity_main
id
值。
再来看看
ViewInject
注解:



ViewInject

@Target(ElementType.FIELD)
说明该组件作用在成员变量上。
@Retention(RetentionPolicy.RUNTIME)
说明该注解会保留到JVM运行时。
int value();
说明注解参数类型为
int
,而
int parentId() default 0
说明可以填写一个父View的id,默认为0。
关于
java
注解的基本使用,大家可以自行搜索。
现在我们知道了两个注解的作用:
ContentView
注解是用来注入主布局界面的,而
ViewInject
注解是用来注入具体控件的。
那么当
MainActivity
回调
onCreate
方法时,因为继承了
BaseActivity
,所以自然就走到
BaseActivity
onCreate
方法:



BaseActivity

那么接下来我们看看这个
x.view().inject(this);
中的
inject(this)
实现方法吧:



x.view().inject(this)

先获取了传入
Activity
Class
对象,然后将这个
Class
作为参数传入
findContentView(handlerType)
方法,从名字就可以看出该方法肯定是获取
ContentView
的注解对象的:



findContentView(handlerType)

该方法也是比较简单的,首先判断了
thisCls
是不是
null
,或者是不是非法的
Class
,看下
IGNORED
:



IGNORED

这里看到
IGNORED
是一个
HashSet
保存了一些需要忽略的
Class
对象。
通过检测后
ContentView contentView = thisCls.getAnnotation(ContentView.class);
这句代码其实就是获取
thisCls
上的注解
ContentView
类,这里就是
MainActivity
上的
ContentView
注解。
如果获取的
ContentView
null
就继续在
thisCls
的父类中获取。
这样我们分析完了
findContentView(handlerType)
方法,作用就是获取传入类或父类上的注解
ContentView
类。
我们继续回到
inject()
方法,获取到
ContentView
注解后,如果不为
null
那么就通过
int viewId = contentView.value();
获取注解中填写的
id
值,也就是
R.layout.activity_main
的值,然后



获取注解中填写的 id 值

之后就是通过反射获取
MainActivity
上的
setContentView
方法,然后再反射调用该方法,将布局id值
R.layout.activity_main
设置上去,这样就完成了
MainActivity
布局的设置,基本原理就是通过注解+反射,还是比较简单的。
最后一句代码:



injectObject()

首先我们看看方法中的第三个参数是个
ViewFinder
对象,将
MainActivity
通过构造传递进去了。
先看看这个
ViewFinder
类的内容:



ViewFinder

该类的主要作用就是用于获取绑定的
View
对象,就是将
View
Activity
findViewById
方法进行封装,先大致了解下。
然后再返回
injectObject()
方法,该方法较长,一部分一部分的贴出:



检测参数是否合法

首先还是检测是否是合法的类,然后:



递归调用

这里进行递归调用,然后是重点:



核心代码

146行是获取所有声明的字段,这里我们就是
MainActivity
中的字段了,然后开始循环。
150-157行是检测字段是不是合法的类型,如果合法才能继续。
159行就是获取字段上的
ViewInject
注解类。
162行就是如果获取到的
ViewInject
类不为
null
,就将
ViewInject
注解中填写的
view
id和父
view
id作为参数传递给
finder
类来获取绑定的
View
对象,回顾下
MainActivity
中的字段:



被注解的字段

可以看到只写了
view
的id,并没有写父
view
的id,那么父
view
的id就是默认值
0
了。
明白了再看看
ViewFinder
类中:



findViewById方法

36-38行就是说如果
pid
大于
0
,那么就获取父
view
对象,看看
findViewById()
方法:



重载的 findViewById方法

这里就是封装了
findViewById
方法,适用于
View
对象或者
Activity
,这里我们是
Activity

继续看40-45行,因为我们没有写
pid
所以代码执行44行,这样我们就获取到了绑定的
View
对象了。
这样我们再回到
ViewInjectorImpl
类的
injectObject(...)
方法:



反射设置 view 对象

这里就很清楚了,如果获取的
View
对象不为
null
,那么通过反射调用,将
View
对象设置到
field
上,这样就完成了一个视图控件的绑定,过程并不是很复杂。

文/悠嘻侠(简书作者)
原文链接:http://www.jianshu.com/p/7791f3b8c234
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: