Skip to content

Commit 4f94124

Browse files
committed
Site updated: 2019-01-04 19:11:29
1 parent 38e342a commit 4f94124

File tree

3 files changed

+88
-10
lines changed

3 files changed

+88
-10
lines changed

2019/01/04/安卓注解处理器-processor/index.html

+78-6
Original file line numberDiff line numberDiff line change
@@ -79,18 +79,21 @@
7979

8080

8181

82-
<meta name="description" content="知耻而后勇,知弱而图强">
82+
<meta name="description" content="1234title: 安卓注解处理器-processordate: 2019-01-04 19:02:34tags: annotation、processor、自动生成java文件category: 注解 最近在学习安卓开源框架发现,很多的开源框架都使用到了注解处理器,例如EventBus3.0。本文通过一个简单的Demo来介绍如何使用注解处理器。Demo链接为https://github.com">
8383
<meta name="keywords" content="Android">
8484
<meta property="og:type" content="article">
8585
<meta property="og:title" content="夏勇的个人博客">
8686
<meta property="og:url" content="http://yoursite.com/2019/01/04/安卓注解处理器-processor/index.html">
8787
<meta property="og:site_name" content="夏勇的个人博客">
88-
<meta property="og:description" 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">
8989
<meta property="og:locale" content="zh-Hans">
90-
<meta property="og:updated_time" content="2019-01-04T11:09:33.772Z">
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:11:19.343Z">
9193
<meta name="twitter:card" content="summary">
9294
<meta name="twitter:title" content="夏勇的个人博客">
93-
<meta name="twitter:description" 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">
9497

9598

9699

@@ -367,7 +370,51 @@ <h1 class="post-title" itemprop="name headline"></h1>
367370

368371

369372

370-
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-&gt;Module-&gt;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 &#123;</span><br><span class="line"> String name() default &quot;test&quot;;</span><br><span class="line">&#125;</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文件) —&gt; .class文件 —&gt; 内存中的字节码。</p>
396+
<p>2、注解@Target表示修饰的注解能使用的范围,ElementType.METHOD表示@AnnotationTest注解只能作用在方法上。</p>
397+
<h3 id="注解处理器"><a href="#注解处理器" class="headerlink" title="注解处理器"></a>注解处理器</h3><p>参照上部分,在工程中new-&gt;Module-&gt;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 &apos;com.google.auto.service:auto-service:1.0-rc2&apos;</span><br><span class="line">// 该Module依赖上部分建立的annotation Module</span><br><span class="line">implementation project(&apos;:annotation&apos;)</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&#123;</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) &#123;</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">&#125;</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&lt;String&gt; getSupportedAnnotationTypes() &#123;</span><br><span class="line"> Set&lt;String&gt; supportAnnotationTypes = new HashSet&lt;&gt;();</span><br><span class="line"> supportAnnotationTypes.add(AnnotationTest.class.getCanonicalName());</span><br><span class="line"> return supportAnnotationTypes;</span><br><span class="line">&#125;</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() &#123;</span><br><span class="line"> return SourceVersion.latestSupported();</span><br><span class="line">&#125;</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&lt;? extends TypeElement&gt; annotations, RoundEnvironment roundEnvironment) &#123;</span><br><span class="line"> // 打印日志</span><br><span class="line"> mMessager.printMessage(Diagnostic.Kind.NOTE, &quot;process start&quot;);</span><br><span class="line"> Map&lt;String, List&lt;String&gt;&gt; collectInfos = new HashMap&lt;&gt;();</span><br><span class="line"> for (TypeElement annotation: annotations)&#123;</span><br><span class="line"> Set&lt;? extends Element&gt; elements = roundEnvironment.getElementsAnnotatedWith(annotation);</span><br><span class="line"> for (Element element: elements)&#123;</span><br><span class="line"> // 检查element是否符合我们定义的规范</span><br><span class="line"> if (!checkValid(element))&#123;</span><br><span class="line"> mMessager.printMessage(Diagnostic.Kind.NOTE, &quot;checkValid not pass&quot;);</span><br><span class="line"> return false;</span><br><span class="line"> &#125;else &#123;</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&lt;String&gt; methods = collectInfos.get(classFullName);</span><br><span class="line"> if (methods == null)&#123;</span><br><span class="line"> methods = new ArrayList&lt;&gt;();</span><br><span class="line"> collectInfos.put(classFullName, methods);</span><br><span class="line"> &#125;</span><br><span class="line"> methods.add(methodName);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> for (Map.Entry&lt;String, List&lt;String&gt;&gt; entry: collectInfos.entrySet())&#123;</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"> &#125;</span><br><span class="line"></span><br><span class="line"> return true;</span><br><span class="line">&#125;</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)&#123;</span><br><span class="line"> options.encoding = &quot;UTF-8&quot;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
415+
<h3 id="Lib"><a href="#Lib" class="headerlink" title="Lib"></a>Lib</h3><p>在工程中new-&gt;Module-&gt;Android Library ,新建一个Android Library Module,封装接口给调用方使用,具体逻辑请参考demo。</p>
416+
<p>最终该demo的功能是点击Hello world文字,会依此执行MainActivity中使用@AnnotationTest注解的方法。</p>
417+
371418

372419
</div>
373420

@@ -435,8 +482,17 @@ <h1 class="post-title" itemprop="name headline"></h1>
435482

436483

437484

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+
438494

439-
<section class="site-overview-wrap sidebar-panel sidebar-panel-active">
495+
<section class="site-overview-wrap sidebar-panel">
440496
<div class="site-overview">
441497
<div class="site-author motion-element" itemprop="author" itemscope="" itemtype="http://schema.org/Person">
442498

@@ -481,6 +537,22 @@ <h1 class="post-title" itemprop="name headline"></h1>
481537
</section>
482538

483539

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+
484556

485557

486558

index.html

+9-3
Original file line numberDiff line numberDiff line change
@@ -367,9 +367,15 @@ <h1 class="post-title" itemprop="name headline">
367367

368368

369369

370-
371-
372-
370+
<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>
371+
<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。</p>
372+
<!--noindex-->
373+
<div class="post-button text-center">
374+
<a class="btn" href="/2019/01/04/安卓注解处理器-processor/#more" rel="contents">
375+
阅读全文 &raquo;
376+
</a>
377+
</div>
378+
<!--/noindex-->
373379

374380

375381
</div>

0 commit comments

Comments
 (0)