AOP:面向切面編程(Aspect-Oriented Programming)。如果說,OOP如果是把問題劃分到單個模塊的話,那么AOP就是把涉及到眾多模塊的某一類問題進行統(tǒng)一管理。
Android AOP就是通過預(yù)編譯方式和運行期動態(tài)代理實現(xiàn)程序功能的統(tǒng)一維護的一種技術(shù)。利用AOP可以對業(yè)務(wù)邏輯的各個部分進行隔離,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性,提高開發(fā)效率。本文僅做知識介紹,相關(guān)詳細(xì)內(nèi)容不做過多描述,全部代碼在項目T-MVP。
話不多說,先上圖:
AOP在Java后臺,已經(jīng)被各路大神研發(fā)出各種框架風(fēng)生水起,例如SSH、SpringMVC等等殿堂級框架。在Android端,近年來也是異軍突起。
APT
代表框架:DataBinding,Dagger2, ButterKnife, EventBus3 、DBFlow、AndroidAnnotation
注解處理器 Java5 中叫APT(Annotation Processing Tool),在Java6開始,規(guī)范化為 Pluggable Annotation Processing。Apt應(yīng)該是這其中我們最常見到的了,難度也最低。定義編譯期的注解,再通過繼承Proccesor實現(xiàn)代碼生成邏輯,實現(xiàn)了編譯期生成代碼的邏輯。
使用姿勢 :
1、建立一個java的Module,寫一個繼承AbstractProcessor的類
2、在工具類里處理我們自定義的注解、生成代碼:
3、在Gradle中添加 dependencies annotationProcessor project(':apt')
低版本需要使用第三方插件 apply plugin: 'com.neenbedankt.android-apt'
然后apt project(':apt')
生成的源代碼在build/generated/source/apt下可以看到
難點:
就apt本身來說沒有任何難點可言,難點一在于設(shè)計模式和解耦思想的靈活應(yīng)用,二在與代碼生成的繁瑣,你可以手動字符串拼接,當(dāng)然有更高級的玩法用squareup的javapoet,用建造者的模式構(gòu)建出任何你想要的源代碼。
想詳細(xì)了解可以看官網(wǎng)或這篇博客:
Android 利用 APT 技術(shù)在編譯期生成代碼
優(yōu)點:
它的強大之處無需多言,看代表框架的源碼,你可以學(xué)到很多新姿勢。總的一句話:它可以做任何你不想做的繁雜的工作,它可以幫你寫任何你不想重復(fù)代碼。懶人福利,老司機必備神技,可以提高車速,讓你以任何姿勢漂移。它可以生成任何源代碼供你在任何地方使用,就像劍客的劍,快疾如風(fēng),無所不及。
AspectJ
代表框架: Hugo(Jake Wharton)
AspectJ支持編譯期和加載時代碼注入,在開始之前,我們先看看需要了解的詞匯:
Advice(通知): 典型的 Advice 類型有 before、after 和 around,分別表示在目標(biāo)方法執(zhí)行之前、執(zhí)行后和完全替代目標(biāo)方法執(zhí)行的代碼。
Joint point(連接點): 程序中可能作為代碼注入目標(biāo)的特定的點和入口。
Pointcut(切入點): 告訴代碼注入工具,在何處注入一段特定代碼的表達(dá)式。
Aspect(切面): Pointcut 和 Advice 的組合看做切面。例如,在本例中通過定義一個 pointcut 和給定恰當(dāng)?shù)腶dvice,添加一個了內(nèi)存緩存的切面。
Weaving(織入): 注入代碼(advices)到目標(biāo)位置(joint points)的過程。
下面這張圖簡要總結(jié)了一下上述這些概念。
使用姿勢:
1、建立一個android lib Module,定義一個切片,處理自定義注解,和添加切片邏輯
2、自定義一個gradle插件,使用 AspectJ 的編譯器(ajc,一個java編譯器的擴展),對所有受 aspect 影響的類進行織入,在 gradle 的編譯 task 中增加額外配置,使之能正確編譯運行。
3、在grade中apply plugin:com.app.plugin.AspectjPlugin
生成的class文件在build/intermediates/classes下可以看到
難點:
AspectJ語法比較多,但是掌握幾個簡單常用的,就能實現(xiàn)絕大多數(shù)切片,完全兼容Java(純Java語言開發(fā),然后使用AspectJ注解,簡稱@AspectJ。)想詳細(xì)了解可以看官網(wǎng)或這篇博客:
深入理解AndroidAOP
優(yōu)點:
AspectJ除了hook之外,AspectJ還可以為目標(biāo)類添加變量,接口。另外,AspectJ也有抽象,繼承等各種更高級的玩法。它能夠在編譯期間直接修改源代碼生成class,強大的團戰(zhàn)切入功能,指哪打哪,鞭辟入里。有了此神器,編程亦如庖丁解牛,游刃而有余。
Javassist
代表框架:熱修復(fù)框架HotFix 、Savior(InstantRun)等
Javassist作用是在編譯器間修改class文件,與之相似的ASM(熱修復(fù)框架女媧)也有這個功能,可以讓我們直接修改編譯后的class二進制代碼,首先我們得知道什么時候編譯完成,并且我們要趕在class文件被轉(zhuǎn)化為dex文件之前去修改。在Transfrom這個api出來之前,想要在項目被打包成dex之前對class進行操作,必須自定義一個Task,然后插入到predex或者dex之前,在自定義的Task中可以使用javassist或者asm對class進行操作。而Transform則更為方便,Transfrom會有他自己的執(zhí)行時機,不需要我們插入到某個Task前面。Tranfrom一經(jīng)注冊便會自動添加到Task執(zhí)行序列中,并且正好是項目被打包成dex之前。
使用姿勢
1、定義一個buildSrc module添加自定義Plugin
2、自定義Transform
3、在Transform里處理Task,通過inputs拿到一些東西,處理完畢之后就輸出outputs,而下一個Task的inputs則是上一個Task的outputs。
4、使用Javassist操作字節(jié)碼,添加新的邏輯或者修改原有邏輯
5、在grade中apply plugin:com.app.plugin.MyPlugin
修改后的class文件在build/intermediates/transforms/MyTrans下可以看到
難點:
相比ASM,Javassist對java極度友好的api更容易快速上手,難點在思想的應(yīng)用,小到切片邏輯的控制,如本例中的性能log打印日志,大到宏觀的熱修復(fù),插件化中對preDex的操作修改,劍客精神到了這一層級,已經(jīng)是上帝視角,無所不能。
優(yōu)點:
由于Javassist可以直接操作修改編譯后的字節(jié)碼,直接繞過了java編譯器,所以可以做很多突破限制的事情,例如,跨dex引用,解決熱修復(fù)中CLASS_ISPREVERIFIED的問題。
想詳細(xì)了解可以看官網(wǎng)或這篇博客:
Android熱補丁動態(tài)修復(fù)技術(shù)
基于Instant Run思想的HotFix方案實現(xiàn)
AOP
AOP技術(shù)常用在以下方面:
1、日志記錄:業(yè)務(wù)埋點
2、持久化
3、性能監(jiān)控:性能日志
4、數(shù)據(jù)校驗:方法的參數(shù)校驗
5、緩存:內(nèi)存緩存和持久緩存
6、權(quán)限檢查:業(yè)務(wù)權(quán)限(如登陸,或用戶等級)、系統(tǒng)權(quán)限(如拍照定位)
7、異常處理
利用AOP技術(shù)將這些功能代碼從業(yè)務(wù)邏輯代碼中劃分出來,通過對這些行為的分離,可以將它們獨立到非業(yè)務(wù)邏輯。無論是日后新增,或是修改,都手到擒來易如反掌。
例如新的tmvp的demo中 apt用于生成實例化工廠,替換掉(對于小項目來說)繁雜冗余的Dagger2,實現(xiàn)了初始化功能的aop ;aspectj 的切片主要用在緩存和日志,用注解實現(xiàn)方法級別的內(nèi)存緩存和方法耗時日志;Javassist 這里只是做了個示例,也是通過注解實現(xiàn)方法耗時日志的自動打印功能,當(dāng)然這些都只是AOP的九牛一毛,AOP還可以做很多事,彌補OOP的不足,把所有跨對象的橫切面關(guān)注點的功能都可以提取出來用AOP去實現(xiàn) ,好處顯而易見,將來要改的地方永遠(yuǎn)只有一處,而不是像OOP那樣牽扯很多模塊很多代碼很多類。
當(dāng)然還有更多未知的可能,需要等各位大俠來研究開發(fā),讓Aop在Android上的應(yīng)用更加廣泛。
PS:剛發(fā)現(xiàn)一個歪果仁的框架 http://6thsolution.github.io/EasyMVP 基于Clean Architecture 用了apt、aspectj、javassisit 不多說趕緊看源代碼學(xué)習(xí)去了
QQ群:AndroidMVP 555343041
更新日志:
2017/1/31:AOP新增SysPermissionAspect支持動態(tài)申請系統(tǒng)權(quán)限切片,輕松適配6.0+
2017/1/27:AOP新增DbRealmAspect支持Realm數(shù)據(jù)庫,數(shù)據(jù)庫突破你想像的簡單(年夜特供)
2017/1/8: 使用Apt封裝Retrofit生成ApiFactory替換掉所有的Repository,狂刪代碼
2017/1/7: 使用DataBinding替換掉所有的ButterKnife,狂刪代碼
2017/1/6: 使用DataBinding替換掉所有的ViewHolder,狂刪代碼,從此邁向新時代
2016/12/30:使用Apt生成全局路由TRouter,更優(yōu)雅的頁面跳轉(zhuǎn),支持傳遞參數(shù)和共享view轉(zhuǎn)場動畫
2016/12/29:去掉BaseMultiVH新增VHClassSelector支持更完美的多ViewHolder
2016/12/28:使用Apt生成全局的ApiFactory替代所有的Model
2016/12/27:增加了BaseMultiVH擴展支持多類型的ViewHolder
2016/12/26:抽離CoreAdapterPresenter優(yōu)化TRecyclerView
安卓AOP實戰(zhàn):面向切片編程
Android實用技巧之:用好泛型,少寫代碼
安卓AOP實戰(zhàn):APT打造極簡路由
全局路由TRouter,更優(yōu)雅的頁面跳轉(zhuǎn)
安卓AOP實戰(zhàn):Javassist強擼EventBus
加入OkBus,實現(xiàn)注解傳遞事件
安卓AOP三劍客:APT,AspectJ,Javassist
1、去掉所有反射>2、新增apt初始化工廠,替換掉了dagger2。>3、新增aop切片,處理緩存和日志