Android:xUtils3 浅析(一)——视图注入

【转载请注明出处】
笔者: DrkCore
CSDN 原文: Android:xUtils3浅析(一)——视图注入

2018-3-17 更新

这篇文章其实已经写了近两年了,现在看来写的还算通顺。在今天(2018-3-17)将之从 CSDN 搬运到 GitHub Page 页面的时候又稍微做了点润色,同时不禁感慨 Android 开发框架的进步之快。

从今天的眼光来看笔者认为 xUtils3 的视图模块确实有点跟不上时代的。xUtils 最初的思路就是做一个大而全的框架,涵盖数据库、网络请求、视图注入和图片加载的功能足够支撑起一个应用的开发,这个思路也被 xUtils3 所继承。但是随着业界的发展各种“专注于干好一件事”的新框架们开始崭露头角,将各自领域做到极致的它们多多少少已经开始蚕食 xUtils 框架原本占领着的市场了。

就拿视图注入这块内容来说,笔者目前使用的解决方案是 Butterknife。其特点想必大家也有所了解,不再细说。针对其没有 ContentView 注解的问题笔者还特地开发了个新框架来弥补这一点,有兴趣的请移步笔者的开源地址 GitHub: ContentViewAnnotation

当然,讲这些话并不是为了批判 xUtils 有多不好,放到 Android 刚刚起步的那几年有几个框架能和 xUtils 比肩呢。现在的话,如果想要了解如何完整的写出一个新框架,想要学习框架编程的思想的话,将之细细研读想必还是会大有收获的。

前言

如果你能点进这篇博文,说明你和笔者一样也是使用 xUtils 的 Android 开发者。作为国内老牌的框架 xUtils 的功能禁得起考验。在版本升级到了 xUtils3 后笔者果断 fork 了一波。

在接下来的篇幅中笔者将为你简单介绍一下 xUtils3 的视图注入模块的实现方式。

该模块是 xUtils3 四大模块中最简单的一个,其所有的逻辑都在主线程中完成且基本只在界面启动时调用一次,因而将之作为理解 xUtils3 源码的第一步而言再合适不过了。

在旧版中视图模块除了查找视图外还能使用注解将资源(比如 String 或者 Drawable 等)绑定到成员变量上,但是 xUtils3 中该模块就只专心做视图注入和事件绑定了。这倒算是一件好事,因为说实话资源注入用的很少而且到要用资源时才加载会更轻快一些。

废话不多说了,让我们进入正题。

要讲视图注入模块首先要讲的肯定是注解,如果你对注解还不了解的话请点此度娘传送门自行学习,在之后的章节中默认你们已经了解了注解的基本使用方法。

在 xUtils3 的 org.xutils.view.annotation 包中可以看到我们平常使用的三个注解:ViewInject、ContentView、Event。

从 ViewInject 注解开始

ViewInject 注解本身没什么内容:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewInject {
   

    int value();

    /* parent view id */
    int parentId() default 0;
}

大体就是用两个属性标出视图的位置信息,int value()自然就是用来标志视图的 id 的而 int parentId()是用来标志目标所在的父视图的id,这样就可以通过查找父视图来区分两个同id的视图(如果你愿意在一个 xml 里使用同一个 id 两次的话)。

注解本身只起到了标注的作用,真正的逻辑实现则写在了 ViewInjectorImpl 类的方法中:

void injectObject(Object handler, Class handlerType, ViewFinder finder)

形参中的 handler 是需要绑定视图的实例,其类可以是 Activity、Fragment 甚至是自定义 ViewHolder,只要有成员变量被 ViewInject 标注即可;

handlerType 自然是handler.getClass(),不解释;

需要注意的是 ViewFinder。我们知道在 Androd 中拥有 findViewById(int) 这个方法的只有 View 和 Activity,而 ViewFinder 是二者的装饰者,挺简单的,具体实现瞟一眼源码你就懂了。

接着让我来看看 injectObject 中使用 ViewInject 的关键代码:

// inject view
// 这里我们可以看到使用反射获取定义的成员变量
Field[] fields = handlerType.getDeclaredFields();
if (fields != null && fields.length > 0) {
   
    for (Field field : fields) {
   
        //跳过无法注入或者不需要注入的字段
        Class<?> fieldType = field.getType();
        if (
        /* 不注入静态字段 */     Modifier.isStatic(field.getModifiers()) ||
        /* 不注入final字段 */    Modifier.isFinal(field.getModifiers()) ||
        /* 不注入基本类型字段 */  fieldType.isPrimitive(
  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值