上一节我们已经将自动生成注解代码部分介绍完毕,今天这篇文章是自定义Android注解系列的最后一篇文章。希望大家这一路走来有所收获。

经过前面的了解,我们三大部分:butterknife-annotations、butterknife-compiler与butterknife-bind。现在就剩下最后一部分butterknife-bind。该部分是对我们前面定义的注解变量与自动生成的代码进行绑定,即调用我们自动生成的代码。

那么我们还是来看下butterknife-bind模板库的结构:

只有Butterknife一个类,在这之前我们还需将前面我们已经定义好的module引入

dependencies {...compile project(path: ':butterknife-annotations')
}

有了之前的基础,我们Make Project项目工程,之后就可以找到MainActivity$Binding类,或者直接在/app/build/generated/source/kapt/debug/目录下查找。

Bind

MainActivity$Binding在构造方法中就已经调用了我们的需要的bindView与setOnClickListener方法。所以我们需要使用的话只需实例化即可。但由于我们是该类是通过注解处理器自动生成的,所以我们并不知道它的类名全称(这里我们相当于查看了源码,才知道是以$Binding结尾)。这样我们是不能通过new关键字来实例化。如此,我们又该如何实例化它呢?这时我们再来看butterknife-bind中的唯一的类Butterknife

public class Butterknife {private Butterknife() {}private static <T extends Activity> void initialization(T target, String suffix) {Class<?> tClass = target.getClass();String className = tClass.getName();try {Class<?> bindingClass = tClass.getClassLoader().loadClass(className + suffix);Constructor<?> constructor = bindingClass.getConstructor(tClass);constructor.newInstance(target);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}public static void bind(Activity activity) {initialization(activity, ConstantUtils.BINDING_BUTTERKNIFE_SUFFIX);}
}

在initialization方法中,我们通过java反射来实例化我们需要的MainActivity$Binding。既然我们已经知道自动生成的类是由原始类(MainActivity)+后缀($Binding)组成。所以可以很好的使用java反射来实例化所需的类。对于外界的调用只需使用bind方法,传入需要绑定的类即可。

Use

到这里,所以的准备工作已经完成。接下来我们可以开始在MainActivity中使用。首先将定义的库进行依赖

dependencies {...implementation project(':butterknife-bind')kapt project(':butterknife-compiler')
}

然后在MainActivity中使用

class MainActivity : AppCompatActivity() {@BindView(R.id.public_service, R.string.public_service)lateinit var sName: TextView@BindView(R.id.personal_wx, R.string.personal_wx)lateinit var sPhone: TextViewoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)Butterknife.bind(this)}@OnClick(R.id.public_service)fun nameClick(view: View) {Toast.makeText(this, getString(R.string.public_service_click_toast), Toast.LENGTH_LONG).show()}@OnClick(R.id.personal_wx)fun phoneClick(view: View) {Toast.makeText(this, getString(R.string.personal_wx_click_toast), Toast.LENGTH_LONG).show()}
}

我们使用@BindView绑定View的Id与默认值;使用@OnClick绑定点击事件;使用Butterknife.bind(this)绑定自定义的注解代码。这样我们已经完成了与开源库Butterknife相似的功能。

progurad

现在你在模拟器或者真机上跑着非常完美,然后你不小心切换到release版本并且开启了混淆功能。这时你会发现mmp居然没有效果。为什么呢?debug与release的区别,绝大数情况下都是混淆惹的祸。我们在实例化自动生成的类时使用的是java反射机制,所以一旦混淆了我们的java反射就找不到我们指定的类名,这样自然也就没有效果了。

那么我们现在又该如何解决呢?别急,是否还记得在系列的Part1我们自定义注解变量中定义了@Keep

在MainActivity$Binding类上我们使用了@Keep来标识该类,通过该标识告诉proguard不去混淆使用@Keep标记的类。要达到这种效果,我们还需经过以下两个步骤:

1.在butterknife-bind的proguard-rules.pro文件中添加如下代码

-keep class com.idisfkj.butterknife.annotations.Keep**
-keep @com.idisfkj.butterknife.annotations.Keep public class *
-keepclassmembers @com.idisfkj.butterknife.annotations.Keep class ** {*;}

2.为了是依赖库的混淆生效,我们还需使用consumerProguardFiles声明

    defaultConfig {...consumerProguardFiles 'proguard-rules.pro' //依赖库混淆生效}

完成这两步后我们在重新构建release版本,这时程序完美运行。终于可以轻松的休息会了!

End

自定义Android注解系列完美收工,希望通过这三部曲能够帮助大家学会如何实现注解库。最后希望大家点赞支持一下,谢谢!

文章中的代码都可以在Github中获取到。使用时请将分支切换到feat_annotation_processing

相关文章

自定义Android注解Part1:注解变量

自定义Android注解Part2:代码自动生成

关注

公众号:怪谈时间到了

自定义Android注解Part3:绑定相关推荐

  1. 自定义Android注解Part2:代码自动生成

    上一期我们已经把butterknife-annotations中的注解变量都已经定义好了,分别为BindView.OnClick与Keep. 如果你是第一次进入本系列文章,强烈推荐跳到文章末尾查看上篇 ...

  2. 开发自己的山寨Android注解框架

    目录 开发自己的山寨Android注解框架 开发自己的山寨Android注解框架 参考 Github黄油刀 Overview 在上一章我们学习了Java的注解(Annotation),但是我想大家可能 ...

  3. 玩转java(Android)注解

    2019独角兽企业重金招聘Python工程师标准>>> 玩转java(Android)注解 1. java标准(原生)注解概览 Java API 中,在java.lang.java. ...

  4. Android应用程序绑定服务(bindService)的过程源代码分析

    Android应用程序组件Service与Activity一样,既可以在新的进程中启动,也可以在应用程序进程内部启动:前面我们已经分析了在新的进程中启动Service的过程,本文将要介绍在应用程序内部 ...

  5. 自定义依赖注解无效_关于Apt注解实践与总结【包含20篇博客】

    超详细!安卓巴士开发者大会嘉宾及主题介绍 目录介绍 00.注解系列博客汇总 01.什么是apt 02.annotationProcessor和apt区别 03.项目目录结构 04.该案例作用 05.使 ...

  6. Android 注解与注解处理器简述

    Android 注解与注解处理器简述 前言 正文 一.注解 ① 注解类型 ② 注解生命周期 ③ 注解参数 二.注解处理器 ① 注册 ② 配置 三.使用 ① 接口 ② 反射 ③ 使用 ④ 强化 四.源码 ...

  7. Android 注解处理器使用攻略

    上一篇写了JavaPoet使用攻略,了解了JavaPoet用法.那么我们就可以结合今天的Annotation Processing Tool(APT)来自定义注解处理器. 注解处理器简单解释就是收集我 ...

  8. Android注解之从入门到并没有放弃

    定义 注解是代码里的特殊标记,这些标记可以在编译.类加载.运行时被读取,并执行相应的处理. 分类 注解分为标准注解和元注解: 标准注解 @Override:对覆盖超类中的方法进行标记,如果被标记的方法 ...

  9. Android注解处理器APT技术简介

    Android注解处理器APT技术简介 APT是什么 例子 APT有什么用 (好处) APT原理 (为什么) APT实践 (怎么做) 参考 APT是什么 APT全称"Annotation P ...

最新文章

  1. python3遍历电子表格_python 3读取多个文本写入同一个excel,每个文本对应各自独立的 sheet 页...
  2. jQuery的选择器分类
  3. 自学linux指令分析-find
  4. JQuery常用的代码片段
  5. winform直接控制云台_速学指南,2分钟学会Feiyu pocket口袋云台的隐藏功能操作
  6. php显示时间,php实现用已经过去多长时间的方式显示时间
  7. 三议(巧用:before和inline-block伪元素解决)跨浏览器不定长宽,中心为基点,百分比定位~...
  8. spark学习-scala版写的SparkSQL程序读取Hbase表注册成表SQL查询
  9. Hadoop源码篇--Reduce篇
  10. 饭卡管理系统学生E-R图
  11. Lenovo System x 硬件Windows Server驱动下载
  12. 美团点评 2019校招 前端方向职位试卷在线考试
  13. 轻轻松松背单词软件测试,完美单词王app
  14. php面试会考计算机网络,计算机网络常见面试题整理
  15. Altium Designer2019——PCB 设计叠层说明
  16. mac go版本升级
  17. 第一部分day5 文件操作
  18. 蓝牙耳机哪款好用?这些选购小技巧帮你选到更适合你的蓝牙耳机!
  19. 软件体系结构的第二次实验(解释器风格与管道过滤器风格)
  20. 第九章SpringBoot整合Spring Data JPA

热门文章

  1. Uber无人车撞人视频公布,究竟哪儿出问题了?
  2. 人人都是作曲家:基于深度神经网络的音乐风格迁移
  3. 重磅 | 机器学习大神Bengio最新论文发布,专注RNN优化难题,将在NIPS提出新概念fraternal dropout
  4. 系统、应用监控的缜密思路,性能瓶颈的克星
  5. 高并发下秒杀商品,你必须知道的9个细节
  6. 实现数据“一键脱敏”,Sharding Sphere帮你搞定
  7. 非常有必要了解的Springboot启动扩展点
  8. 没有这 29 款插件的 Chrome 是没有灵魂的!
  9. 5分钟带你读「大清」微积分!160多年前清朝数学家撰写文言文版高等数学
  10. 清华旷视:让VGG再次伟大!