Android高级学习之xUtils3源码解析

来源:互联网 发布:软件测试加班 编辑:程序博客网 时间:2024/05/21 01:48

xUtils3简介

1.xUtils 包含了很多实用的android工具.
2.xUtils 支持超大文件(超过2G)上传,更全面的http请求协议支持(11种谓词),拥有更加灵活的ORM,更多的事件注解支持且不受混淆影响…
3.xUtils 最低兼容Android 4.0 (api level 14). (Android 2.3?)
4.xUtils3变化较多所以建立了新的项目不在旧版(github.com/wyouflf/xUtils)上继续维护, 相对于旧版本:
HTTP实现替换HttpClient为UrlConnection, 自动解析回调泛型, 更安全的断点续传策略.
支持标准的Cookie策略, 区分domain, path…
事件注解去除不常用的功能, 提高性能.
数据库api简化提高性能, 达到和greenDao一致的性能.
图片绑定支持gif(受系统兼容性影响, 部分gif文件只能静态显示), webp; 支持圆角, 圆形, 方形等裁剪, 支持自动旋转…

使用

使用Gradle构建时添加一下依赖即可:

compile 'org.xutils:xutils:3.3.42'

Utils3在初始化的时候必须在自定义的Application中的onCreate()方法来完成初始化,代码为x.Ext.init(this);,首先就涉及到了这个x类,我们打开可以看到x类是所有模块的入口而
x.Ext这个内部类中提供了一系列的静态成员变量,和对应的set方法,对应了xutils提供的几个功能模块。
我们接着看init()方法:

public static void init(Application app) {            TaskControllerImpl.registerInstance();            if (Ext.app == null) {                Ext.app = app;            }        }

很明显是将Application绑定到app上,方便全局调用。

View注入

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

public static ViewInjector view() {        if (Ext.viewInjector == null) {            ViewInjectorImpl.registerInstance();        }        return Ext.viewInjector;    }

返回一个viewInjector对象,而viewInjector仅仅是一个接口,接口中定义了view,Avtivity,以及ViewHolder,fragment的注入方法view(),以满足各个场景的使用。那么到它的实现类中再看
ViewInjectorImpl.registerInstance();是如何初始化的:

public static void registerInstance() {        if (instance == null) {            synchronized (lock) {                if (instance == null) {                    instance = new ViewInjectorImpl();                }            }        }        x.Ext.setViewInjector(instance);    }

一个很经典的单例设计模式。很明显的是通过registerInstance()创建一个viewInjector对象。接着看它是如何和Activity绑定的:
在Sample项目中,可以很明显的看到两种注解:
@ContentView(id)和@ViewInject(id):ContentView注解是用来注入主布局界面的,而ViewInject注解是用来注入具体控件的。
@ContentView(R.layout.activity_main)放入的就是布局activity_main的id值
@Target(ElementType.TYPE)说明了该注解作用于类,接口或者枚举类型上。
@Retention(RetentionPolicy.RUNTIME)说明该注解会一直保留到JVM运行时。
@Target(ElementType.FIELD)说明该组件作用在成员变量上。
@Retention(RetentionPolicy.RUNTIME)说明该注解会保留到JVM运行时。

那么当MainActivity回调onCreate方法时,因为继承了BaseActivity,所以自然就走到
那么接下来我们看看这个x.view().inject(this);中的inject(this)实现方法:
第三个参数是个ViewFinder对象,将MainActivity通过构造传递进去了。
该类的主要作用就是用于获取绑定的View对象,就是将View和Activity的findViewById方法进行封装
如果获取的View对象不为null,那么通过反射调用,将View对象设置到field上,这样就完成了一个视图控件的绑定,过程并不是很复杂。

事件的绑定

注解是通过Event这个注解类:
Class type()就是需要的事件类,默认是click事件
首先还是调用x.view().inject(this);,之后就是将Event注解绑定在方法上,我们还是看看x.view().inject(this)做了什么:
该方法首先是判断了有没有ContentView注解,如果有的话会通过来给Activity设置布局,最后调用injectObject方法绑定activity,该方法的后半部分就是通过注解,动态代理和反射机制来完成事件的绑定的。先获取了activity所声明的所有方法,实际上也是获取添加了Event注解的方法,之后进入循环。如果方法是静态的或不是private类型的,那么不对方法进行检查,然后对方法的注解进行检查:
如果Event注解存在,则获取到控件的id和父控件id两个数组:根据的ID和当前的接口类型获取已经缓存的接口实例对象,比如根据View.id和View.OnClickListener.class两个键获取这个View的OnClickListener对象,接着判断:
  如果接口实例对象不为空,则获取接口对象对应的动态代理对象
  如果动态代理对象的handler和当前handler相同,则为动态代理对象添加代理方法
接着获取view控件需要绑定的方法,这里根据setOnClickListener方法名,和View.OnClickListener.class获取setOnClickListener的Method对象,然后通过invoke方法,将View.OnClickListener的代理实例对象设置给view控件,这样就完成了view事件的绑定。我们需要一个View.OnClickListener的实体类设置给view对象的,不能将接口直接设置给view,所以需要这个代理实例对象listener,这也就是动态代理的意义所在。

0 0