超详细!安卓巴士开发者大会嘉宾及主题介绍

目录介绍

  • 00.注解系列博客汇总

  • 01.什么是apt

  • 02.annotationProcessor和apt区别

  • 03.项目目录结构

  • 04.该案例作用

  • 05.使用说明

  • 06.编译期注解生成代码[点击事件案例]

  • 07.运行期注解案例[setContentView案例]

  • 08.使用注解替代枚举

  • 09.使用注解搭建路由[综合案例]

    • 9.1 搭建路由条件

    • 9.2 通过注解去实现路由跳转

    • 9.3 自定义路由Processor编译器

    • 9.4 利用apt生成路由映射文件

    • 9.5 路由框架的设计

    • 9.6 路由参数的传递和接收

    • 9.7 为何需要依赖注入

    • 9.8 Activity属性注入

    • 9.9 路由开源库的使用

关于apt实践与总结开源库地址:

https://github.com/yangchong211/YCApt

文中含有众多超链,可点击左下角“阅读原文”相应位置查看。

00.注解系列博客汇总

0.1 注解基础系列博客

  • 01.Annotation注解详细介绍

    1.Annotation库的简单介绍    2.@Nullable和@NonNull    3.资源类型注释    4.类型定义注释    5.线程注释    6.RGB颜色纸注释    7.值范围注释    8.权限注释    9.重写函数注释    10.返回值注释    11.@Keep注释    12.@SuppressWarnings注解    13.其他
  • 02.Dagger2深入分析,待更新

  • 03.注解详细介绍

    • 什么是注解,注解分类有哪些?自定义注解分类?运行注解案例展示分析,以一个最简单的案例理解注解……使用注解替代枚举,使用注解限定类型

  • 04.APT技术详解

    • 什么是apt?理解注解处理器的作用和用途……android-apt被替代?annotationProcessor和apt区别? 什么是jack编译方式?

  • 06.自定义annotation注解

    • @Retention的作用?@Target(ElementType.TYPE)的解释,@Inherited注解可以被继承吗?Annotation里面的方法为何不能是private?

  • 07.注解之兼容kotlin

    • 后期更新

  • 08.注解之处理器类Processor

    • 处理器类Processor介绍,重要方法,Element的作用,修饰方法的注解和ExecutableElement,了解修饰属性、类成员的注解和VariableElement……

  • 10.注解遇到问题和解决方案

    • 无法引入javax包下的类库,成功运行一次,修改代码后再运行就报错

  • 11.注解代替枚举

    • 在做内存优化时,推荐使用注解代替枚举,因为枚举占用的内存更高,如何说明枚举占用内存高呢?这是为什么呢?

  • 12.注解练习案例开源代码

    • 注解学习小案例,比较系统性学习注解并且应用实践。简单应用了运行期注解,通过注解实现了setContentView功能;简单应用了编译器注解,通过注解实现了防暴力点击的功能,同时支持设置时间间隔;使用注解替代枚举;使用注解一步步搭建简单路由案例。结合相应的博客,在来一些小案例,从此应该对注解有更加深入的理解……

0.2 注解系列博客问题答疑

  • 13.0.0.1 什么是注解?系统内置的标准注解有哪些?SuppressWarnings用过没?Android中提供了哪些与线程相关的注解?

  • 13.0.0.2 什么是apt?apt的难点和优势?什么是注解处理器?抽象处理器中四个方法有何作用?annotationProcessor和apt区别?

  • 13.0.0.3 注解是怎么分类的?自定义注解又是怎么分类的?运行期注解原理是什么?实际注解案例有哪些?

  • 13.0.0.4 在自定义注解中,Annotation里面的方法为何不能是private?Annotation里面的方法参数有哪些?

  • 13.0.0.5 @Inherited是什么意思?注解是不可以继承的,这是为什么?注解的继承这个概念该如何理解?

  • 13.0.0.6 什么是依赖注入?依赖注入案例举例说明,有哪些方式,具备什么优势?依赖查找和依赖注入有什么区别?

  • 13.0.0.7 路由框架为何需要依赖注入,不用的话行不行?路由用什么方式注入,这些注入方式各具何特点,为何选择注解注入?

  • 13.0.0.8 实际开发中使用到注解有哪些,使用注解替代枚举?如何通过注解限定传入的类型?为何说枚举损耗性能?

01.什么是apt

  • 什么是apt

    • APT,就是Annotation Processing Tool的简称,就是可以在代码编译期间对注解进行处理,并且生成Java文件,减少手动的代码输入。注解我们平时用到的比较多的可能会是运行时注解,比如大名鼎鼎的retrofit就是用运行时注解,通过动态代理来生成网络请求。编译时注解平时开发中可能会涉及的比较少,但并不是说不常用,比如我们经常用的轮子Dagger2, ButterKnife, EventBus3 都在用,所以要紧跟潮流来看看APT技术的来龙去脉。

  • 编译时注解。

    • 也有人叫它代码生成,其实他们还是有些区别的,在编译时对注解做处理,通过注解,获取必要信息,在项目中生成代码,运行时调用,和直接运行手写代码没有任何区别。而更准确的叫法:APT - Annotation Processing Tool

  • 大概原理

    • Java API 已经提供了扫描源码并解析注解的框架,开发者可以通过继承 AbstractProcessor 类来实现自己的注解解析逻辑。APT 的原理就是在注解了某些代码元素(如字段、函数、类等)后,在编译时编译器会检查 AbstractProcessor 的子类,并且自动调用其 process() 方法,然后将添加了指定注解的所有代码元素作为参数传递给该方法,开发者再根据注解元素在编译期输出对应的 Java 代码

02.annotationProcessor和apt区别

  • annotationProcessor和apt区别

    • Android 官方的 annotationProcessor 同时支持 javac 和 jack 编译方式,而 android-apt 只支持 javac 方式。当然,目前 android-apt 在 Android Gradle 插件 2.2 版本上面仍然可以正常运行,如果你没有想支持 jack 编译方式的话,可以继续使用 android-apt。

    • 目前比如一些常用框架dagger2,butterKnife,ARouter等,都支持annotationProcessor

  • 什么是jack编译方式?

    • Jack (Java Android Compiler Kit)是新的Android 编译工具,从Android 6.0 开始加入,替换原有的编译工具,例如javac, ProGuard, jarjar和 dx。它主要负责将java代码编译成dex包,并支持代码压缩,混淆等。

  • Jack工具的主要优势

    • 完全开放源码,源码均在AOSP中,合作伙伴可贡献源码

    • 加快编译源码,Jack 提供特殊的配置,减少编译时间:pre-dexing, 增量编译和Jack编译服务器.

    • 支持代码压缩,混淆,重打包和multidex,不在使用额外单独的包,例如ProGuard。

03.项目目录结构

  • 项目目录结构如图:

    • app:Demo

    • AptAnnotation:java Library主要放一些项目中需要用到的自定义注解及相关代码

    • AptApi:Android Library. 是我们真正对外发布并交由第三方使用的库,它引用了apt-jar包

    • AptCompiler:java Library主要是应用apt技术处理注解,生成相关代码或者相关源文件,是核心所在。

04.该案例作用

  • 前期仅仅是为了学习,同时先让demo运行起来,虽然网上很多讲解apt的博客写的很详细,但是还是有必要结合实际案例练习一下。

  • 使用apt实现点击事件【编译期注解生成代码】

    • 在一定时间内,按钮点击事件只能执行一次。未到指定时间,不执行点击事件。

  • 使用apt实现setContentView功能【运行期注解案例】

    • 使用简单的注解,便可以设置布局,等效于setContentView(R.layout.activity_main)

  • 使用apt实现路由【综合型案例】

    • 比较全面的介绍从零起步,一步一步封装简易的路由开源库。一共用10篇博客记录了大部分的过程,想要更加深入了解,欢迎clone该项目。

05.使用说明

  • 如下所示

    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //初始化OnceClick,并设置点击事件间隔是2秒        OnceInit.once(this,2000);    }

    @OnceClick(R.id.tv_1)    public void Click1(){        Log.d("tag--------------------","tv_1");    }

06.编译期注解生成代码

  • 如下所示,在app/build/generated/source/apt/debug/MainActivity_Once_Proxy目录下

    // 编译生成的代码,不要修改    // 更多内容:https://github.com/yangchong211    package com.ycbjie.ycapt;

    import android.view.View;    import com.ycbjie.api.Finder;    import com.ycbjie.api.AbstractInjector;

    public class MainActivity$$_Once_Proxy<T extends MainActivity> implements AbstractInjector<T> {

        public long intervalTime;

        @Override        public void setIntervalTime(long time) {            intervalTime = time;        }

        @Override        public void inject(final Finder finder, final T target, Object source) {            View view;            view = finder.findViewById(source, 2131165325);            if(view != null){                view.setOnClickListener(new View.OnClickListener() {                long time = 0L;                @Override                public void onClick(View v) {                    long temp = System.currentTimeMillis();                    if (temp - time >= intervalTime) {                        time = temp;                        target.Click1();                    }                }});            }            view = finder.findViewById(source, 2131165326);            if(view != null){                view.setOnClickListener(new View.OnClickListener() {                long time = 0L;                @Override                public void onClick(View v) {                    long temp = System.currentTimeMillis();                    if (temp - time >= intervalTime) {                        time = temp;                        target.Click2(v);                    }                }});            }      }

    }

07.运行期注解案例

  • 首先先定义自定义注解

    //@Retention用来修饰这是一个什么类型的注解。这里表示该注解是一个运行时注解。    @Retention(RetentionPolicy.RUNTIME)    //@Target用来表示这个注解可以使用在哪些地方。比如:类、方法、属性、接口等等。    //这里ElementType.TYPE 表示这个注解可以用来修饰:Class, interface or enum declaration。    //当你用ContentView修饰一个方法时,编译器会提示错误。    @Target({ElementType.TYPE})    //这里的interface并不是说ContentView是一个接口。    //就像申明类用关键字class。申明枚举用enum。申明注解用的就是@interface。    public @interface ContentView {        //返回值表示这个注解里可以存放什么类型值。        int value();    }
  • 然后需要在activity中做注解解析

    @SuppressLint("Registered")    public class ContentActivity extends AppCompatActivity {        @Override        protected void onCreate(Bundle savedInstanceState) {            super.onCreate(savedInstanceState);            //注解解析            //遍历所有的子类            for (Class c = this.getClass(); c != Context.class; c = c.getSuperclass()) {                assert c != null;                //找到修饰了注解ContentView的类                ContentView annotation = (ContentView) c.getAnnotation(ContentView.class);                if (annotation != null) {                    try {                        //获取ContentView的属性值                        int value = annotation.value();                        //调用setContentView方法设置view                        this.setContentView(value);                    } catch (RuntimeException e) {                        e.printStackTrace();                    }                    return;                }            }        }    }
  • 关于如何使用,注意你写的Activity需要实现ContentActivity,才能让注解生效

    @ContentView(R.layout.activity_four)    public class FourActivity extends ContentActivity {

        @Override        protected void onCreate(Bundle savedInstanceState) {            super.onCreate(savedInstanceState);            findViewById(R.id.tv_1).setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View v) {                    Toast.makeText(FourActivity.this,"运行期注解",Toast.LENGTH_SHORT).show();                }            });        }    }

09.使用注解搭建路由[综合案例]

  • 9.1 ARouter路由解析

    • 比较详细地分析了阿里路由库

  • 9.1 搭建路由条件

    • 为何需要路由?实现路由方式有哪些,这些方式各有何优缺点?使用注解实现路由需要具备的条件以及简单原理分析……

  • 9.2 通过注解去实现路由跳转

    • 自定义Router注解,Router注解里有path和group,这便是仿照ARouter对路由进行分组。然后看看注解生成的代码,手写路由跳转代码。

  • 9.3 自定义路由Processor编译器

    • Processor介绍,重要方法,Element的作用,修饰方法的注解和ExecutableElement

  • 9.4 利用apt生成路由映射文件

    • 在Activity类上加上@Router注解之后,便可通过apt来生成对应的路由表,那么究竟是如何生成的代码呢?

    • 在组件化开发中,有多个module,为何要在build.gradle配置moduleName,又是如何通过代码拿到module名称?

    • process处理方法如何生成代码的,又是如何写入具体的路径,写入文件的?

    • 看完这篇文章,应该就能够理解上面这些问题呢!

  • 9.5 路由框架的设计和初始化

    • 编译期是在你的项目编译的时候,这个时候还没有开始打包,也就是你没有生成apk呢!路由框架在这个时期根据注解去扫描所有文件,然后生成路由映射文件。这些文件都会统一打包到apk里,app运行时期做的东西也不少,但总而言之都是对映射信息的处理,如执行执行路由跳转等。那么如何设计框架呢?

    • 生成的注解代码,又是如何把这些路由映射关系拿到手,或者说在什么时候拿到手比较合适?为何注解需要进行初始化操作?

    • 如何得到得到路由表的类名,如何得到所有的routerAddress---activityClass映射关系?

  • [9.6 路由框架设计注意要点]()

    • 需要注意哪些要点?

  • 9.7 为何需要依赖注入

    • 有哪些注入的方式可以解耦,你能想到多少?路由框架为何需要依赖注入?路由为何用注解进行依赖注入,而不是用反射方式注入,或者通过构造方法注入,或者通过接口方式注入?

  • 9.8 Activity属性注入

    • 在跳转页面时,如何传递intent参数,或者如何实现跳转回调处理逻辑?

  • 9.9 路由开源库的使用

    • 不带参数直接跳转

        @Router(path = Path.six)        public class SixActivity extends AppCompatActivity {

            @Override            protected void onCreate(@Nullable Bundle savedInstanceState) {                super.onCreate(savedInstanceState);                setContentView(R.layout.activity_six);            }

        }

        ARouter.getsInstance().build(Path.six)                    .navigation(MainActivity.this, new NavigationCallback() {                @Override                public void onFound(Postcard postcard) {                    Log.e("NavigationCallback","找到跳转页面");                }

                @Override                public void onLost(Postcard postcard) {                    Log.e("NavigationCallback","未找到");                }

                @Override                public void onArrival(Postcard postcard) {                    Log.e("NavigationCallback","成功跳转");                }            });
  • 带参数跳转

        @Router(path = Path.five)        public class FiveActivity extends AppCompatActivity {

            @Extra            String title;

            @Override            protected void onCreate(@Nullable Bundle savedInstanceState) {                super.onCreate(savedInstanceState);                setContentView(R.layout.activity_five);                //添加这行代码,实际上就是自动生成了下面获取参数值的代码                ARouter.getsInstance().inject(this);                //如果不添加插入注解,则可以直接用下面的代码。                //Intent intent = getIntent();                //String title = intent.getStringExtra("title");                Toast.makeText(this, "title=" + title, Toast.LENGTH_SHORT).show();            }

        }

        Bundle bundle = new Bundle();        bundle.putString("title","标题-------------");        ARouter.getsInstance()                .build(Path.five)                .withBundle(bundle)                .navigation();
  • 路由注解生成的代码位置


关于apt实践与总结开源库地址:
https://github.com/yangchong211/YCApt

大家都在看

线上活动 | 解救深陷暗恋的Mob福利菌!

从零开始跨平台开发 Flutter 1.0 环境搭建

23种设计模式及案例整理分享

一篇文章告诉你MVC、MVP、MVVM

欢迎前往安卓巴士博客区投稿,技术成长于分享

期待巴友留言,共同探讨学习

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

  1. 关于Apt注解实践与总结【包含20篇博客】

    YCApt关于apt方案实践与总结 目录介绍 00.注解系列博客汇总 01.什么是apt 02.annotationProcessor和apt区别 03.项目目录结构 04.该案例作用 05.使用说明 ...

  2. java 博客系统_讲解开源项目:5分钟搭建私人Java博客系统

    本文适合刚学习完 Java 语言基础的人群,跟着本文可了解和运行 Tale 项目.示例均在 Windows 操作系统下演示 本文作者:HelloGitHub-秦人 HelloGitHub 推出的< ...

  3. 自定义依赖注解无效_最详细的自定义Spring Boot Starter开发教程

    1.前言 随着Spring的日渐臃肿,为了简化配置.开箱即用.快速集成,Spring Boot 横空出世.目前已经成为 Java 目前最火热的框架了.平常我们用Spring Boot开发web应用.S ...

  4. hexo评论_【前端简历加分】hexo框架搭建个人博客站点,手把手教学

    最近,粉丝们在金九银十期间也是不断的面试,有比较多的毕业生说我在这个期间出多一些面试题,上几期都是倾向于面试文章,这期出一次简历加分项操作,使用hexo框架搭建个人博客. 作为应届毕业生或者1-3年工 ...

  5. .net编写抽奖的文档_使用开源文档工具docsify,用写博客的姿势写文档

    前提 ❝ 下面的简介摘抄自docsify的官网 https://docsify.js.org 中的简介 ❞ 「docsify」是一个神奇的文档网站生成器.他可以快速帮你生成文档网站.不同于GitBoo ...

  6. mysql的单页应用框架搭建_采用vue+webpack构建的单页应用——私人博客MintloG诞生记...

    介绍 项目地址:https://github.com/jrainlau/MintloG (特别乱,参考就好-_-|||) MintloG是我在五天之内完全由自己开发的私人博客,前端技术方案采用了vue ...

  7. android自定义控件几种,Android 自定义View一个控件搞定多种水波纹涟漪扩散效果 - CSDN博客...

    效果图 实现思路 这个效果实现起来并不难,重要的是思路 此View满足了多种水波纹涟漪扩散效果,这要求它能满足很多的变化 根据上面的样式,可以看出此View需要满足以下变化 圆圈从中心可循环向外扩散 ...

  8. 基于python的个人博客_一款基于 Django 的极简主义个人博客系统

    shadow_blog 介绍 shadow_blog 是一款基于 Django 的极简主义个人博客,已应用在苍茫误此生博客 前端基于 Boundless-UI,风格简约.支持响应式布局, 已适配主流的 ...

  9. 我的第一篇博客_在Linux下用C++编写的德州扑克游戏

    文章目录 序言 抽象思路 类的抽象 牌类(Card) 一组牌(GroupCards) 牌堆(DeckCards) 牌堆类设计 初始化卡牌 洗牌 与手牌公共牌的关系 手牌(HandCards) 公共牌( ...

最新文章

  1. libsvm库简介及使用
  2. mybatis mysql 配置文件_Mybatis配置文件详解(4)
  3. 滴滴裁员补偿丰厚,员工称裁出幸福感?
  4. 多读多写多实践---给初学编程者的建议
  5. 公益:开放一台Nacos服务端给各位Spring Cloud爱好者
  6. Java课堂测试——一维数组
  7. linux下获取本机的获取内网和外网地址
  8. python中csv库_关于python 自带csv库的使用心得 附带操作实例以及excel下乱码的解决...
  9. 编程语言的“别样”编年史
  10. 深度神经网络移动终端GPU加速实践
  11. SpringMVC多种参数接收
  12. base,override,virtual
  13. 细说进程、应用程序域与上下文之间的关系(三)—— 深入了解.NET上下文
  14. CS231n-assignment1详解
  15. 扫描文件怎么设置到服务器,如何为扫描仪添加局域网功能
  16. ApacheCN 活动汇总 2019.8.30
  17. 主成分分析法确定权重
  18. html注册页面连接mysql_注册界面连接数据库
  19. 很好的东子(干货很多)--把一个函数变成全局的方法及slideToggle()
  20. 计算机图形学基础知识-光照材质

热门文章

  1. linux常用调试,linux下gdb常用的调试命令
  2. Tomcat配置解析
  3. jsp标签在JavaScript中使用时,可能会出现的一个问题。
  4. jsp中获取list长度
  5. ADB 基础命令使用
  6. CSS3实现小黄人动画
  7. scala初学之函数定义、流程控制、异常处理入门
  8. 解决微信小程序新建项目没有样式问题,以及官方demo
  9. Linux版本配置环境变量,如何linux环境下配置环境变量过程图解
  10. java 工具类sort_Java 通用排序工具类ListSortUtils