zoukankan      html  css  js  c++  java
  • xUtils3源码分析(一):view的绑定

    概述

    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


    ActivityonCreate方法中,调用:
    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_mainid值。
    再来看看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,所以自然就走到BaseActivityonCreate方法:


    BaseActivity


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


    x.view().inject(this)


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


    findContentView(handlerType)

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


    IGNORED


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


    获取注解中填写的 id


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


    injectObject()

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


    ViewFinder

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


    检测参数是否合法


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


    递归调用


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


    核心代码

    146行是获取所有声明的字段,这里我们就是MainActivity中的字段了,然后开始循环。
    150-157行是检测字段是不是合法的类型,如果合法才能继续。
    159行就是获取字段上的ViewInject注解类。
    162行就是如果获取到的ViewInject类不为null,就将ViewInject注解中填写的viewid和父viewid作为参数传递给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
    著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
  • 相关阅读:
    在eclipse中快速多行注释的方法
    Android开发:去掉Activity的头部标题栏及全屏显示
    C#的Process类的一些用法
    C#中隐式操作CMD命令行窗口 (转)
    我的INI 配置文件读写动态库
    Android高手进阶教程(五)之----Android 中LayoutInflater的使用!
    Android高手进阶教程(六)之----Android 中MenuInflater的使用(布局定义菜单)!
    Android Menu 之 optionsMenu 详解
    centos安装php扩展
    linux 权限
  • 原文地址:https://www.cnblogs.com/Sharley/p/5669774.html
Copyright © 2011-2022 走看看