Android 打造編譯時註解解析框架 這只是一個開始

發表於2015-05-15

1、概述

記得很久以前,寫過幾篇部落格,容我列舉一下:

Android 進階 教你打造 Android 中的 IOC 框架 【ViewInject】 (上)

Android 進階 教你打造 Android 中的 IOC 框架 【ViewInject】 (下)

Android 框架煉成 教你如何寫元件間通訊框架EventBus

大家可以關注下這些部落格的評論,不管咋樣,大家對於效能的考慮還是很多呢,一看到這類的框架,不解析還好,只要解析出來是註解和反射,必然的一個問題就是:這樣會不會影響效能呀?嗯,肯定會有效能的損耗,那麼我就再考慮有沒有更好的實現方式呢?既可以實現注入,還能保證效能無損耗呢?好訊息來說,是有噠,對沒錯,上述部落格實現方式,包括xutils , afinal 目前的注入使用的都是執行時註解,當然了還有一類註解叫做編譯時註解。

2、註解

說道註解,竟然還有各種分類,得,這記不住,我們從註解的作用來反推其分類,幫助大家記憶,然後舉例強化大家的記憶,話說註解的作用:

1、標記一些資訊,這麼說可能太抽象,那麼我說,你見過@Override、@SuppressWarnings等,這類註解就是用於標識,可以用作一些檢驗

2、執行時動態處理,這個大家見得應該最多,在執行時拿到類的Class物件,然後遍歷其方法、變數,判斷有無註解宣告,然後做一些事情。類似上述三篇博文中的做法。

3、編譯時動態處理,這個呢?就是我們今天的主角了,一般這類註解會在編譯的時候,根據註解標識,動態生成一些類或者生成一些xml都可以,在執行時期,這類註解是沒有的~~會依靠動態生成的類做一些操作,因為沒有反射,效率和直接呼叫方法沒什麼區別~~~

關於3,大家不明白,沒事,下文會詳談,使用這類註解的專案有:ParcelableGenerator、butterknife 、androidannotaion等。

作用談完了,那麼如果你看到一個註解的宣告你如何去判斷他的作用呢?例如:

1秒鐘告訴我,它的作用是什麼?哈,大家可能會鬱悶,擦,我咋知道。其實可以看這個註解上面的@Retention後面的值,設定的為CLASS,說明就是編譯時動態處理的。

這個值是一個列舉:有三個:SOURCE、RUNTIME、CLASS , 到這裡,是不是,搜噶,這三個11對應於上面三個作用。

好了,說完了註解的作用以及判斷方式,那麼大家可以看到除了@Retention還有個@Target,@Target的值呢是一個ElementType[]陣列。什麼意思呢?就是標明這個註解能標識哪些東西,比如類、變數、方法、甚至是註解本身(元註解)等。這個在:Android 進階 教你打造 Android 中的 IOC 框架 【ViewInject】 (上)有詳細說明。

好了,到此註解告一段落,大家只要記得註解的作用,以及如何去定義一個註解就好。

接下來進入我們的主題編譯時註解。

對了,我建立了一個公眾號,會推送一些開源專案、最新部落格、視訊等,關於部落格涉及到的東西,也會提前給大家通知,可以關注一下,謝謝,左側欄目,微信掃描即可。

3、編譯時註解

那我們說一下編寫過程。

1、建立一個類,繼承AbstractProcessor

這個類上可以新增註解:

@SupportedAnnotationTypes的值為當前類支援的註解的完整類路徑,支援萬用字元。

@SupportedSourceVersion 標識該處理器支援的原始碼版本

除此以外還有一個@SupportedOptions,這個一般是命令列時候用的,設定一些選項,but,命令列我不熟,因此:略。

注:如果大家找不到AbstractProcessor,記得右鍵build-path add library把jdk加進來。

2、建立resources等檔案。

這個對專案的一個結構有著固定的要求,下面我通過一張圖來說:

可以看到,在我們的專案中呢,還需要建立一個resources這樣的source folder ,右鍵 new sources folder即可。

然後在裡面建立META-INF/services/javax.annotation.processing.Processor檔案,這個檔案中去寫我們處理器的類完整路徑。

經過上述兩部,我們的編寫環境就OK了。

4、完整例子

下面我們通過一個例子來給大家演示編譯時動態生成資料,我們的效果是這樣的,使用者編寫一堆bean,例如User類,我們通過註解提取屬性動態生成一個json檔案,以及一個代理類,注意是編譯時生成。

注:以下為一個教學示例,無任何使用價值。

那麼我們依然分為步驟來做:

1、建立編寫環境

javax.annotation.processing.Processor裡面寫的是:com.zhy.annotationprocess.processor.BeanProcessor

我們還建立了一個註解:

哈,一秒鐘告訴我,哪一類作用的註解。

2、動態生成資料

1、首先明確一下我們的目標:

我們有很多bean類,例如:

看到有兩個普通的bean,上面宣告瞭我們的註解,如果類上宣告註解我們就將其所有的變數都生成一個json描述檔案;如果僅僅是成員變數呢?那我們只提取宣告的成員變數來動態生成。

類似如下的描述檔案:

是不是覺得沒撒用處,其實用處大大滴,以後我們會驗證。

2、編寫BeanProcessor

程式碼略長,但是註釋很清除,我來解釋一下,基本分為兩個過程:1、找出標識註解的類或成員變數,封裝到maps中;2、遍歷maps為每個類建立json檔案。我們把檔案輸出到了f://apt_test資料夾中,如果你沒有f盤神馬的,自行修改目錄。

3、使用

到此,我們寫完了~~那麼如何用呢?

1、匯出jar

為了更好的演示,以及省篇幅,我錄成gif

注意我選擇的一些核取方塊,和一些預設核取方塊的選中狀態,我將其放在桌面上~~

2、新建一個android或java專案

將jar拷貝到libs下,如果是java專案,需要自己建立lib資料夾,自己手動引用。

然後就開始編寫bean吧:我這裡就寫了兩個類,一個User,一個Article,上面貼過程式碼了。

3、啟用annotation processor

這裡我是eclipse,大家如果是maven專案或者是別的什麼IDE,自行進行網路搜尋,這裡有個Android Studio下的使用,自己點選哈,其實命令列也可以。

下面我們eclipse依然是個gif,不然得截一堆圖片:

假設我們的jar已經拷貝到專案中了,進行如下操作

操作完成以後,那麼就可以去f://apt_test中

開啟即可看到:

ok,這樣的話,我們一個簡單的annotation processor的教程就搞定了~~如果想學,一定要去試,各種試,不要怕麻煩,要是簡單誰都會,那還有什麼意義~~

這是一個非常簡單的例子,那麼具體到我們的專案中如何使用呢?鑑於篇幅,可能只能在下一篇給大家繼續了。不過庫的雛形已經形成:

5、HyViewInject

ok,這就是基於上述的一個庫,主要用於Android的控制元件的注入,類似butterknife,尚在完善中,歡迎大家使用,fork or star ,我們一起完善。

sample的效果圖:

第一個Activity中一個TextView和ListView,第二個Activity一個TextView和Fragment,主要測試了Activity、Fragment、Adapter中注入控制元件。

github地址:點選傳送,尚在完善中,歡迎大家使用,fork or star ,我們一起完善。

相關文章