|
79 | 79 |
|
80 | 80 |
|
81 | 81 |
|
82 |
| -<meta name="description" content="1234title: 安卓注解处理器-processordate: 2019-01-04 19:02:34tags: annotation、processor、自动生成java文件category: 注解 最近在学习安卓开源框架发现,很多的开源框架都使用到了注解处理器,例如EventBus3.0。本文通过一个简单的Demo来介绍如何使用注解处理器。Demo链接为https://github.com"> |
| 82 | +<meta name="description" content="知耻而后勇,知弱而图强"> |
83 | 83 | <meta name="keywords" content="Android">
|
84 | 84 | <meta property="og:type" content="article">
|
85 | 85 | <meta property="og:title" content="夏勇的个人博客">
|
86 | 86 | <meta property="og:url" content="http://yoursite.com/2019/01/04/安卓注解处理器-processor/index.html">
|
87 | 87 | <meta property="og:site_name" content="夏勇的个人博客">
|
88 |
| -<meta property="og:description" content="1234title: 安卓注解处理器-processordate: 2019-01-04 19:02:34tags: annotation、processor、自动生成java文件category: 注解 最近在学习安卓开源框架发现,很多的开源框架都使用到了注解处理器,例如EventBus3.0。本文通过一个简单的Demo来介绍如何使用注解处理器。Demo链接为https://github.com"> |
| 88 | +<meta property="og:description" content="知耻而后勇,知弱而图强"> |
89 | 89 | <meta property="og:locale" content="zh-Hans">
|
90 |
| -<meta property="og:image" content="http://yoursite.com/2019/01/04/安卓注解处理器-processor/框架流程.png"> |
91 |
| -<meta property="og:image" content="http://yoursite.com/2019/01/04/安卓注解处理器-processor/annotation.png"> |
92 |
| -<meta property="og:updated_time" content="2019-01-04T11:04:59.216Z"> |
| 90 | +<meta property="og:updated_time" content="2019-01-04T11:09:33.772Z"> |
93 | 91 | <meta name="twitter:card" content="summary">
|
94 | 92 | <meta name="twitter:title" content="夏勇的个人博客">
|
95 |
| -<meta name="twitter:description" content="1234title: 安卓注解处理器-processordate: 2019-01-04 19:02:34tags: annotation、processor、自动生成java文件category: 注解 最近在学习安卓开源框架发现,很多的开源框架都使用到了注解处理器,例如EventBus3.0。本文通过一个简单的Demo来介绍如何使用注解处理器。Demo链接为https://github.com"> |
96 |
| -<meta name="twitter:image" content="http://yoursite.com/2019/01/04/安卓注解处理器-processor/框架流程.png"> |
| 93 | +<meta name="twitter:description" content="知耻而后勇,知弱而图强"> |
97 | 94 |
|
98 | 95 |
|
99 | 96 |
|
@@ -370,51 +367,7 @@ <h1 class="post-title" itemprop="name headline"></h1>
|
370 | 367 |
|
371 | 368 |
|
372 | 369 |
|
373 |
| - <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">title: 安卓注解处理器-processor</span><br><span class="line">date: 2019-01-04 19:02:34</span><br><span class="line">tags: annotation、processor、自动生成java文件</span><br><span class="line">category: 注解</span><br></pre></td></tr></table></figure> |
374 |
| -<p>最近在学习安卓开源框架发现,很多的开源框架都使用到了注解处理器,例如EventBus3.0。本文通过一个简单的Demo来介绍如何使用注解处理器。Demo链接为<a href="https://github.com/cugyong/AnnotationProcessor-sample" target="_blank" rel="noopener">https://github.com/cugyong/AnnotationProcessor-sample</a> ,如果喜欢的话,欢迎大家给star。<a id="more"></a></p> |
375 |
| -<h2 id="Demo需求描述"><a href="#Demo需求描述" class="headerlink" title="Demo需求描述"></a>Demo需求描述</h2><p>用户通过执行一个传入参数为A(类对象)的静态方法,该方法会最终把参数A中加了特定注解的所有方法执行一遍。</p> |
376 |
| -<h2 id="需求实现"><a href="#需求实现" class="headerlink" title="需求实现"></a>需求实现</h2><p><img src="/2019/01/04/安卓注解处理器-processor/框架流程.png" alt="框架流程"></p> |
377 |
| -<p>整个项目分为四个部分:</p> |
378 |
| -<ul> |
379 |
| -<li>注解–要使用的注解类型,这部分通常也可以放在lib中;</li> |
380 |
| -<li>注解处理器–要对注解进行处理的逻辑,包括收集有特定注解类型的方法信息以及生成特定的java文件;</li> |
381 |
| -<li>lib–封装合适的接口,供具体调用方调用;</li> |
382 |
| -<li>sample–具体的调用方逻辑。</li> |
383 |
| -</ul> |
384 |
| -<p>首先新建一个安卓工程,点击运行展示的是hello world。</p> |
385 |
| -<h3 id="注解"><a href="#注解" class="headerlink" title="注解"></a>注解</h3><p>在上述工程中new->Module->Java Library,新建一个Java Library Module,命名为annotation。在该Module下创建一个文件AnnotationTest.java,</p> |
386 |
| -<p><img src="/2019/01/04/安卓注解处理器-processor/annotation.png" alt="1546591844724"></p> |
387 |
| -<p>AnnotationTest.java里面代码如下:</p> |
388 |
| -<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">@Retention(RetentionPolicy.CLASS)</span><br><span class="line">@Target(ElementType.METHOD)</span><br><span class="line">public @interface AnnotationTest {</span><br><span class="line"> String name() default "test";</span><br><span class="line">}</span><br></pre></td></tr></table></figure> |
389 |
| -<p>1、注解@Retention按生命周期来划分可分为3类:</p> |
390 |
| -<ul> |
391 |
| -<li>RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;</li> |
392 |
| -<li>RetentionPolicy.CLASS:注解被保留到class文件,当jvm加载class文件时候被遗弃,这是默认的生命周期;</li> |
393 |
| -<li>RetentionPolicy.RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在。</li> |
394 |
| -</ul> |
395 |
| -<p>这3个生命周期分别对应于:Java源文件(.java文件) —> .class文件 —> 内存中的字节码。</p> |
396 |
| -<p>2、注解@Target表示修饰的注解能使用的范围,ElementType.METHOD表示@AnnotationTest注解只能作用在方法上。</p> |
397 |
| -<h3 id="注解处理器"><a href="#注解处理器" class="headerlink" title="注解处理器"></a>注解处理器</h3><p>参照上部分,在工程中new->Module->Java Library,新建一个Java Library Module, 在该Module下创建一个文件ProcessorTest.java。在该Module下的build.gradle的dependencies中添加如下配置:</p> |
398 |
| -<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">// 自动为processor注册</span><br><span class="line">implementation 'com.google.auto.service:auto-service:1.0-rc2'</span><br><span class="line">// 该Module依赖上部分建立的annotation Module</span><br><span class="line">implementation project(':annotation')</span><br></pre></td></tr></table></figure> |
399 |
| -<p>com.google.auto.service:auto-service:1.0-rc2依赖的作用是为注解处理器自动注册,它会生成META-INF文件夹。</p> |
400 |
| -<p>注解处理器ProcessorTest的定义如下,其中@AutoService(Processor.class)就是build.gradle中加的依赖帮助其自动注册。</p> |
401 |
| -<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">@AutoService(Processor.class) // 自动为ProcessorTest注册,生成META-INF文件</span><br><span class="line">public class ProcessorTest extends AbstractProcessor{</span><br></pre></td></tr></table></figure> |
402 |
| -<p>注解处理器ProcessorTest主要包含以下几个部分:</p> |
403 |
| -<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">@Override</span><br><span class="line">public synchronized void init(ProcessingEnvironment processingEnvironment) {</span><br><span class="line"> super.init(processingEnvironment);</span><br><span class="line"></span><br><span class="line"> mMessager = processingEnvironment.getMessager();</span><br><span class="line"> mFiler = processingEnvironment.getFiler();</span><br><span class="line">}</span><br></pre></td></tr></table></figure> |
404 |
| -<p>init方法是注解处理器会自动调用的初始化方法,其中mFiler是用来生成java源文件的工具,mMessager是用来打印日志的,它们的具体使用会在后面介绍。</p> |
405 |
| -<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">@Override</span><br><span class="line">public Set<String> getSupportedAnnotationTypes() {</span><br><span class="line"> Set<String> supportAnnotationTypes = new HashSet<>();</span><br><span class="line"> supportAnnotationTypes.add(AnnotationTest.class.getCanonicalName());</span><br><span class="line"> return supportAnnotationTypes;</span><br><span class="line">}</span><br></pre></td></tr></table></figure> |
406 |
| -<p>getSupportedAnnotationTypes()方法返回该注解处理器支持的注解类型,这里返回的就是我们之前声明的新的注解类型@AnnotationTest。</p> |
407 |
| -<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">@Override</span><br><span class="line">public SourceVersion getSupportedSourceVersion() {</span><br><span class="line"> return SourceVersion.latestSupported();</span><br><span class="line">}</span><br></pre></td></tr></table></figure> |
408 |
| -<p>getSupportedSourceVersion()方法一般就按照上述实现就行。</p> |
409 |
| -<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line">@Override</span><br><span class="line">public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnvironment) {</span><br><span class="line"> // 打印日志</span><br><span class="line"> mMessager.printMessage(Diagnostic.Kind.NOTE, "process start");</span><br><span class="line"> Map<String, List<String>> collectInfos = new HashMap<>();</span><br><span class="line"> for (TypeElement annotation: annotations){</span><br><span class="line"> Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(annotation);</span><br><span class="line"> for (Element element: elements){</span><br><span class="line"> // 检查element是否符合我们定义的规范</span><br><span class="line"> if (!checkValid(element)){</span><br><span class="line"> mMessager.printMessage(Diagnostic.Kind.NOTE, "checkValid not pass");</span><br><span class="line"> return false;</span><br><span class="line"> }else {</span><br><span class="line"> ExecutableElement executableElement = (ExecutableElement) element;</span><br><span class="line"> // 获取被注解的方法所在的类</span><br><span class="line"> TypeElement typeElement = (TypeElement) executableElement.getEnclosingElement();</span><br><span class="line"> // 获取类的全名,包括包名</span><br><span class="line"> String classFullName = typeElement.getQualifiedName().toString();</span><br><span class="line"> // 被注解的方法的名字</span><br><span class="line"> String methodName = executableElement.getSimpleName().toString();</span><br><span class="line"> List<String> methods = collectInfos.get(classFullName);</span><br><span class="line"> if (methods == null){</span><br><span class="line"> methods = new ArrayList<>();</span><br><span class="line"> collectInfos.put(classFullName, methods);</span><br><span class="line"> }</span><br><span class="line"> methods.add(methodName);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> for (Map.Entry<String, List<String>> entry: collectInfos.entrySet()){</span><br><span class="line"> mMessager.printMessage(Diagnostic.Kind.NOTE, entry.getKey());</span><br><span class="line"> // 生成java源文件</span><br><span class="line"> createJavaFile(entry.getKey(), entry.getValue());</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> return true;</span><br><span class="line">}</span><br></pre></td></tr></table></figure> |
410 |
| -<p>process方法是我们的主要逻辑处理的地方,主要逻辑就是收集所有有@AnnotationTest注解的方法以及其所在的类信息,然后根据每个类信息,生成一个新的类文件,并在新的类文件的特定方法中调用所有关联的注解方法。生成java源文件将使用Filer对象,具体如何使用请下载demo看源代码。</p> |
411 |
| -<p><strong>注:</strong> </p> |
412 |
| -<p>1、当你点击buid project时,注解处理器将会执行,而Messager对象打印出来的日志信息可以在Gradle Console窗口中看到。</p> |
413 |
| -<p>2、如果你在该Module中使用中文注解,因为该Module为java library,可能会报GBK编码错误,解决办法是在该Module的build.gradle中添加如下代码:</p> |
414 |
| -<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">//指定编译的编码</span><br><span class="line">tasks.withType(JavaCompile){</span><br><span class="line"> options.encoding = "UTF-8"</span><br><span class="line">}</span><br></pre></td></tr></table></figure> |
415 |
| -<h3 id="Lib"><a href="#Lib" class="headerlink" title="Lib"></a>Lib</h3><p>在工程中new->Module->Android Library ,新建一个Android Library Module,封装接口给调用方使用,具体逻辑请参考demo。</p> |
416 |
| -<p>最终该demo的功能是点击Hello world文字,会依此执行MainActivity中使用@AnnotationTest注解的方法。</p> |
417 |
| - |
| 370 | + |
418 | 371 |
|
419 | 372 | </div>
|
420 | 373 |
|
@@ -482,17 +435,8 @@ <h3 id="Lib"><a href="#Lib" class="headerlink" title="Lib"></a>Lib</h3><p>在工
|
482 | 435 |
|
483 | 436 |
|
484 | 437 |
|
485 |
| - <ul class="sidebar-nav motion-element"> |
486 |
| - <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap"> |
487 |
| - 文章目录 |
488 |
| - </li> |
489 |
| - <li class="sidebar-nav-overview" data-target="site-overview-wrap"> |
490 |
| - 站点概览 |
491 |
| - </li> |
492 |
| - </ul> |
493 |
| - |
494 | 438 |
|
495 |
| - <section class="site-overview-wrap sidebar-panel"> |
| 439 | + <section class="site-overview-wrap sidebar-panel sidebar-panel-active"> |
496 | 440 | <div class="site-overview">
|
497 | 441 | <div class="site-author motion-element" itemprop="author" itemscope="" itemtype="http://schema.org/Person">
|
498 | 442 |
|
@@ -537,22 +481,6 @@ <h3 id="Lib"><a href="#Lib" class="headerlink" title="Lib"></a>Lib</h3><p>在工
|
537 | 481 | </section>
|
538 | 482 |
|
539 | 483 |
|
540 |
| - <!--noindex--> |
541 |
| - <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active"> |
542 |
| - <div class="post-toc"> |
543 |
| - |
544 |
| - |
545 |
| - |
546 |
| - |
547 |
| - |
548 |
| - |
549 |
| - <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#Demo需求描述"><span class="nav-text">Demo需求描述</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#需求实现"><span class="nav-text">需求实现</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#注解"><span class="nav-text">注解</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#注解处理器"><span class="nav-text">注解处理器</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Lib"><span class="nav-text">Lib</span></a></li></ol></li></ol></div> |
550 |
| - |
551 |
| - |
552 |
| - </div> |
553 |
| - </section> |
554 |
| - <!--/noindex--> |
555 |
| - |
556 | 484 |
|
557 | 485 |
|
558 | 486 |
|
|
0 commit comments