從 java 註解分析 ButterKnife 工作流程

Anthony發表於2016-06-03

在我的上一篇文章中,絕對不容錯過,ButterKnife使用詳談中,講解了對ButterKnife的使用。這篇文章將接著一篇文章使用之後,對ButterKnife的工作流程進行概要分析。這裡Butterknife分析來自參考自連結How ButterKnife actually works?,並作出部分修改。這裡做一個整理和學習。
考慮到ButterKnife的入口使用java註解,比如。

首先這裡會對java註解(java annotation)分析,然後面接上Butterknife的工作流程。

1 什麼是java註解?

在java語法中,使用@符號作為開頭,並在@後面緊跟註解名。被運用於類,介面,方法和欄位之上,例如:

這其中@Override就是註解。這個註解的作用也就是告訴編譯器,myMethod()方法覆寫了父類中的myMethod()方法。

2 java中內建的註解

java中有三個內建的註解:

2.1 @Override 註解

當我們的子類覆寫父類中的方法的時候,我們使用這個註解,這一定程度的提高了程式的可讀性也避免了維護中的一些問題,比如說,當修改父類方法簽名(方法名和引數)的時候,你有很多個子類方法簽名也必須修改,否則編譯器就會報錯,當你的類越來越多的時候,那麼這個註解確實會幫上你的忙。如果你沒有使用這個註解,那麼你就很難追蹤到這個問題。
示例:

2.2 @Deprecated註解

一個棄用的元素(類,方法和欄位)在java中表示不再重要,它表示了該元素將會被取代或者在將來被刪除。
當我們棄用(deprecate)某些元素的時候我們使用這個註解。所以當程式使用該棄用的元素的時候編譯器會彈出警告。當然我們也需要在註釋中使用@deprecated標籤來標示該註解元素。
示例:

2.3 @SuppressWarnings註解

當我們想讓編譯器忽略一些警告資訊的時候,我們使用這個註解。比如在下面這個示例中,我們的deprecatedMethod()方法被標記了@Deprecated註解,所以編譯器會報警告資訊,但是我們使用了@SuppressWarnings(“deprecation”)也就讓編譯器不在報這個警告資訊了。

3 自定義註解

3.1 來看看一個自定義註解

可以通過下面這種形式新增自己的自定義註解

自定義註解使用@interface來宣告一個註解,這裡對這個自定義的註解進行使用:

可以看到上面的studentAge 和stuStream欄位已經在註解定義階段設定了預設值(當然也可以對這些預設值進行修改),studentName和stuAddress沒有預設值,在使用的時候必須定義值。

 3.2 元註解

在上面的註解定義階段,你一定注意到了這四個註解,那麼他們是什麼呢?

(1).@Target,
(2).@Retention,
(3).@Documented,
(4).@Inherited
這是java 5.0之中引入的四個元註解,元註解也就是負責註解其他的註解。
那麼來分別看看這四個註解是什麼意思?

 

(1)@Target
表示該註解用於什麼地方,可能的ElementType引數包括:
CONSTRUCTOR:構造器的宣告
FIELD:域宣告
LOCAL_VARIABLE:區域性變數宣告
METHOD:方法宣告
PACKAGE:包宣告
PARAMETER:引數宣告
TYPE:類,介面或enum宣告
比如說這個註解表示只能在方法中使用。
(2)@Retention
表示在什麼級別保留此資訊,可選的RetentionPolicy引數包括:
SOURCE:註解僅存在程式碼中,註解會被編譯器丟棄
CLASS:註解會在class檔案中保留,但會被VM丟棄
RUNTIME:VM執行期間也會保留該註解,因此可以通過反射來獲得該註解
比如說這個註解表示VM執行期間也會保留該註解。
(3)@Documented
將註解包含在javadoc中
示例:
(4)@Inherited
允許子類繼承父類中的註解
示例,這裡的MyParentClass 使用的註解標註了@Inherited,所以子類可以繼承這個註解資訊:

4 ButterKnife工作流程解析

有了上面的java註解的基礎知識,那麼接著學習。

4.1 java 註解工作流程
1 註解是在編譯(compile)時期進行處理的。
2 註解處理器(Annotation Processor)讀取java程式碼處理相應的註解,並且生成對應的程式碼。
3 生成的java程式碼被當做普通的java 類再次編譯。
4 註解處理器不能修改存在java輸入檔案,也不能對方法做修改或者新增。
1833901-56e4e67b0f5ed652
java編譯流程
4.2 ButterKnife對應的註解工作流程

當你編譯你的Android工程時,ButterKnife工程中ButterKnifeProcessor類的process()方法會執行以下操作:

1 開始它會掃描Java程式碼中所有的ButterKnife註解@Bind、@OnClick、@OnItemClicked等。
2 當它發現一個類中含有任何一個註解時, ButterKnifeProcessor會幫你生成一個Java類,名字<類名>$$ViewInjector.java,這個新生成的類實現了ViewBinder介面。
3 這個ViewBinder類中包含了所有對應的程式碼,比如@Bind註解對應findViewById(), @OnClick對應了view.setOnClickListener()等等。
4 最後當Activity啟動ButterKnife.bind(this)執行時,ButterKnife會去載入對應的ViewBinder類呼叫它們的bind()方法。
4.3 例項分析

首先ExampleActivity 中使用ButterKnife,如下面所示

接著編譯器就會生成ExampleActivity$$ViewBinder.java檔案

接著在程式執行的時候,流程就是這樣的

1ButterKnife呼叫findViewBinderForClass
(ExampleActivity.class)
方法查詢ExampleActivity$$ViewBinder.java
2 ExampleActivity$$ViewBinder.bind()方法被執行,查詢view以及處理view的型別轉換,並設定給 ExampleActivity.class的相應屬性(這也就是為什麼相應的屬性在ButterKnife中必須為Public的,因為在這裡會進行訪問。當然如果你不考慮效能,也可以採用反射的方式訪問private的屬性,顯然作者沒有做這麼做)
3 onClickListeners也在 ExampleActivity$$ViewBinder.bind()方法方法中被包裝處理點選事件。

1833901-b3fb56fc146df56d

5 參考連結

How ButterKnife actually works?
butterknife 原始碼分析
最新ButterKnife框架原理
Java註解

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

任選一種支付方式

從 java 註解分析 ButterKnife 工作流程 從 java 註解分析 ButterKnife 工作流程

相關文章