天天看點

Butterknife原理分析及自己實作Butternife

butterknife我相信,對大部分做android開發的人都不陌生,這個是供職于square公司的jakewharton大神開發的,目前github的star為 ~12449~ 。使用這個庫,在as中搭配android butterknife zelezny插件,簡直是開發神器,從此擺脫繁瑣的<code>findviewbyid(int id)</code>,也不用自己手動<code>@bind(int id)</code> , 直接用插件生成即可。這種采用注解di元件的方式,在spring中很常見,起初也是在spring中興起的 。今天我們就一探究竟,自己實作一個butterknife <code>(有不會用的,請自行google)</code>。

Butterknife原理分析及自己實作Butternife

butterknife

注解

對butterknife有過了解人 , 注入字段的方式是使用注解<code>@bind(r.id.tv_account_name)</code>,但首先我們需要在<code>activity</code>聲明注入<code>butterknife.bind(activity activity)</code> 。我們知道,注解分為好幾類, 有在源碼生效的注解,有在類檔案生成時生效的注解,有在運作時生效的注解。分别為<code>retentionpolicy.source</code>,<code>retentionpolicy.class</code>,<code>retentionpolicy.runtime</code> ,其中以<code>retentionpolicy.runtime</code>最為消耗性能。而butterknife使用的則是編譯器時期注入,在使用的時候,需要配置<code>classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'</code> , 這個配置說明,在編譯的時候,進行注解處理。要對注解進行處理,則需要繼承<code>abstractprocessor</code> , 在<code>boolean process(set&lt;? extends typeelement&gt; annotations, roundenvironment roundenv)</code>中進行注解處理。

實作方式

知曉了注解可以在編譯的時候進行處理,那麼,我們就可以得到注解的字段屬性與所在類 , 進而生成注入檔案,生成一個注入類的内部類,再進行字段處理 , 編譯之後就會合并到注入類中,達到植入新代碼段的目的。例如:我們注入<code>@vinjector(r.id.tv_show) textview tvshow;</code>我們就可以得到<code>tvshow</code>這個變量與<code>r.id.tv_show</code>這個id的值,然後進行模式化處理<code>injectobject.tvshow = injectobject.findviewbyid(r.id.tv_show);</code> ,再将代碼以内部類的心事加入到元件所在的類中 , 完成一次di(注入) 。

實作流程圖
Butterknife原理分析及自己實作Butternife

view_injector_流程圖

① 首先建立一個視圖注解

② 建立一個注解處理器,用來得到注解的屬性與所屬類

③ 解析注解,分離組合class與屬性

④ 組合class與屬性,生成新的java file

apt生成的java file , 以及模式代碼
Butterknife原理分析及自己實作Butternife

generator java file

使用javac , 編譯時期生成注入類的子類

Butterknife原理分析及自己實作Butternife

viewinject uml

簡要說明:

主要類:

<code>vinjectprocessor</code> ----&gt; 注解處理器 , 需要配置注解處理器

processor内容:

圖示:

Butterknife原理分析及自己實作Butternife

processor config

<code>vinjecthandler</code> ----&gt; 注解處理類 , 主要進行注入類與注解字段進行解析與封裝,将同類的字段使用map集合進行映射。exp: map&lt;class,list&lt;attr&gt;&gt; 。

<code>viewgenerateadapter</code> -----&gt; java file 生成器,将注入的類與屬性,重新生成一個java file,是其注入類的内部類 。

一 , 建立注解 , 對視圖進行注解,r.id.xxx , 是以注解類型是int類型
二, 注解處理器 <code>關于注解處理器配置,上面已經做了說明</code>
對得到的注解進行處理 , 主要是進行注解類型與屬性進行分離合并處理,因為一個類有多個屬性,是以采用map集合,進行存儲,資料結構為:map&lt;string:classname , list&lt;variableelement:element&gt;&gt;
生成java file , 根據擷取的屬性與類,建立一個注入類的内部類

butterknife類型的注解架構,其主要核心就是編譯時期注入, 如果是采用運作時注解的話,那性能肯定影響很大,國内有些di架構就是采用的運作時注解,是以性能上會有所損傷 。原以為很高深的東西,其實剖析過原理之後,也就漸漸明白了,不再視其為高深莫測,我們自己也可以實作同等的功能。

程式員最好的學習方式就是,學習别人的代碼,特别是像jakewharton這樣的大神的代碼,值得研究與學習 , 然後模仿之。

文/逝我(簡書作者)

原文連結:http://www.jianshu.com/p/003be1b75e28

著作權歸作者所有,轉載請聯系作者獲得授權,并标注“簡書作者”。

繼續閱讀