1. 程式人生 > >Android APT 技術淺談

Android APT 技術淺談

安卓AOP三劍客: APT, AspectJ, Javassist

Apt、AspectJ、Javassisit

Android APT

APT(Annotation Processing Tool 的簡稱),可以在程式碼編譯期解析註解,並且生成新的 Java 檔案,減少手動的程式碼輸入。現在有很多主流庫都用上了 APT,比如 Dagger2, ButterKnife, EventBus3 等

代表框架:

  • DataBinding
  • Dagger2
  • ButterKnife
  • EventBus3
  • DBFlow
  • AndroidAnnotation

專案參考

T-MVP

使用姿勢

1,在android工程中,建立一個java的Module,寫一個類繼承AbstractProcessor


    @AutoService(Processor.class) // javax.annotation.processing.IProcessor
    @SupportedSourceVersion(SourceVersion.RELEASE_7) //java
    @SupportedAnnotationTypes({ // 標註註解處理器支援的註解型別
        "com.annotation.SingleDelegate",
        "com.annotation.MultiDelegate"
    })
    public class AnnotationProcessor
extends AbstractProcessor {
public static final String PACKAGE = "com.poet.delegate"; public static final String CLASS_DESC = "From poet compiler"; public Filer filer; //檔案相關的輔助類 public Elements elements; //元素相關的輔助類 public Messager messager; //日誌相關的輔助類 public Types types; @Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) { filer = processingEnv.getFiler(); elements = processingEnv.getElementUtils(); messager = processingEnv.getMessager(); types = processingEnv.getTypeUtils(); new SingleDelegateProcessor().process(set, roundEnvironment, this); new MultiDelegateProcessor().process(set, roundEnvironment, this); return true; } }

2,在繼承AbstractProcessor類中的process方法,處理我們自定義的註解,生成程式碼:


    public class SingleDelegateProcessor implements IProcessor {

    @Override
    public void process(Set<? extends TypeElement> set, RoundEnvironment roundEnv,
                    AnnotationProcessor abstractProcessor) {
    // 查詢註解是否存在
    Set<? extends Element> elementSet =
            roundEnv.getElementsAnnotatedWith(SingleDelegate.class);
    Set<TypeElement> typeElementSet = ElementFilter.typesIn(elementSet);
    if (typeElementSet == null || typeElementSet.isEmpty()) {
        return;
    }

    // 迴圈處理註解
    for (TypeElement typeElement : typeElementSet) {
        if (!(typeElement.getKind() == ElementKind.INTERFACE)) { // 只處理介面型別
            continue;
        }

        // 處理 SingleDelegate,只處理 annotation.classNameImpl() 不為空的註解
        SingleDelegate annotation = typeElement.getAnnotation(SingleDelegate.class);
        if ("".equals(annotation.classNameImpl())) {
            continue;
        }
        Delegate delegate = annotation.delegate();

        // 新增構造器
        MethodSpec.Builder constructorBuilder = MethodSpec.constructorBuilder()
                .addModifiers(Modifier.PUBLIC);

        // 建立類名相關 class builder
        TypeSpec.Builder builder =
                ProcessUtils.createTypeSpecBuilder(typeElement, annotation.classNameImpl());

        // 處理 delegate
        builder = ProcessUtils.processDelegate(typeElement, builder,
                constructorBuilder, delegate);

        // 檢查是否繼承其它介面
        builder = processSuperSingleDelegate(abstractProcessor, builder, constructorBuilder, typeElement);

        // 完成構造器
        builder.addMethod(constructorBuilder.build());

        // 建立 JavaFile
        JavaFile javaFile = JavaFile.builder(AnnotationProcessor.PACKAGE, builder.build()).build();
        try {
            javaFile.writeTo(abstractProcessor.filer);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    }

3,在專案Gradle中新增 annotationProcessor project 引用


    compile project(':apt-delegate-annotation')
    annotationProcessor project(':apt-delegate-compiler')

4,如果有自定義註解的話,建立一個java的Module,專門放入自定義註解。專案與apt Module都需引用自定義註解Module

4-1,主工程:


    compile project(':apt-delegate-annotation')
    annotationProcessor project(':apt-delegate-compiler')

4-2,apt Module:


    compile project(':apt-delegate-annotation')

    compile 'com.google.auto.service:auto-service:1.0-rc2'
    compile 'com.squareup:javapoet:1.4.0'

5,生成的原始碼在build/generated/source/apt下可以看到

難點

就apt本身來說沒有任何難點可言,難點一在於設計模式和解耦思想的靈活應用,二在與程式碼生成的繁瑣,你可以手動字串拼接,當然有更高階的玩法用squareup的javapoet,用建造者的模式構建出任何你想要的原始碼

優點

它的強大之處無需多言,看代表框架的原始碼,你可以學到很多新姿勢。總的一句話:它可以做任何你不想做的繁雜的工作,它可以幫你寫任何你不想重複程式碼。懶人福利,老司機必備神技,可以提高車速,讓你以任何姿勢漂移。它可以生成任何原始碼供你在任何地方使用,就像劍客的劍,快疾如風,無所不及

我想稍微研究一下,APT還可以在哪些地方使用,比如:Repository層?

APT在Repository層的嘗試

瞭解APT與簡單學習之後,搭建Repository層時,發現有一些簡單,重複模版的程式碼

每一次新增新介面都需要簡單地修改很多地方,能不能把一部分程式碼自動生成,減少改動的次數呢?

Repository層

  • IRemoteDataSource, RemoteDataSourceImpl

    遠端資料來源,屬於網路請求相關

  • ILocalDataSource, LocalDataSourceImpl

    本地資料來源,屬於本地資料持久化相關

  • IRepository,RepositoryImpl

    倉庫代理類,代理遠端資料來源與本地資料來源

Repository層APT設計思路

發現在具體實現類中,大多都是以代理類的形式呼叫:方法中呼叫代理物件,方法名稱與引數,返回值型別都相同。顯然可以進行APT的嘗試

簡單的情況,具體實現類中只有一個代理物件

複雜的情況,有多個代理物件,方法內並有一些變化

期望結果:

  • 把RemoteDataSourceImpl自動化生成
  • 把LocalDataSourceImpl自動化生成
  • 把RepositoryImpl自動化生成

自定義註解設計

要想具體實現類自動生成,首先要知道需要什麼:

  • 方便自動生成java檔案的類庫
  • 自動生成類名字是什麼
  • 需要注入的代理物件
  • 讓代理物件代理的方法集

自動生成類名字,代理物件,方法集需要通過自定義註解配置引數的形成,在AbstractProcessor中獲取

Delegate


    @Retention(RetentionPolicy.SOURCE)
    @Target(ElementType.TYPE)
    public @interface Delegate {

    /**
     * delegate class package
     */
    String delegatePackage();

    /**
     * delegate class name
     */
    String delegateClassName();

    /**
     * delegate simple name
     */
    String delegateSimpleName();
    }

SingleDelegate


    @Retention(RetentionPolicy.SOURCE)
    @Target(ElementType.TYPE)
    public @interface SingleDelegate {

    /**
     * impl class name
     */
    String classNameImpl();

    /**
     * delegate data
     */
    Delegate delegate();
    }

MultiDelegate


    @Retention(RetentionPolicy.SOURCE)
    @Target(ElementType.TYPE)
    public @interface MultiDelegate {

    /**
     * impl class name
     */
    String classNameImpl();

    /**
     * delegate list
     */
    Delegate[] Delegates();
    }

處理自定義的註解、生成程式碼

AnnotationProcessor


    @AutoService(Processor.class) // javax.annotation.processing.IProcessor
    @SupportedSourceVersion(SourceVersion.RELEASE_7) //java
    @SupportedAnnotationTypes({ // 標註註解處理器支援的註解型別
        "com.annotation.SingleDelegate",
        "com.annotation.MultiDelegate"
    })
    public class AnnotationProcessor extends AbstractProcessor {

    public static final String PACKAGE = "com.poet.delegate";
    public static final String CLASS_DESC = "From poet compiler";

    public Filer filer; //檔案相關的輔助類
    public Elements elements; //元素相關的輔助類
    public Messager messager; //日誌相關的輔助類
    public Types types;

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        filer = processingEnv.getFiler();
        elements = processingEnv.getElementUtils();
        messager = processingEnv.getMessager();
        types = processingEnv.getTypeUtils();

        new SingleDelegateProcessor().process(set, roundEnvironment, this);
        new MultiDelegateProcessor().process(set, roundEnvironment, this);

        return true;
    }
    }

資料參考

T-MVP

相關推薦

Android APT 技術

安卓AOP三劍客: APT, AspectJ, Javassist Android APT APT(Annotation Processing Tool 的簡稱),可以在程式碼編譯期解析註解,並且生成新的 Java 檔案,減少手動的程式碼輸入。

[技術]初始化語義與賦值語義

真的 class 基本 復制構造函數 spa 數值 復制構造 得到 對數 背景 博主是一個常年使用初始化語義的coder= =,所以經常會遇到這樣的對話 int tmp(0); XXX:誒,你這tmp函數是幹什麽的啊 博主:蛤?我哪裏定義了tmp函數了

Android APP架構(含程式碼)

寫在開頭 不多說,本文圍繞一張圖展開,請查閱,歡迎共同討論,叨擾了。如果你還有什麼需求或者什麼想法,可一起完善此demo一起進步哦!!! 讓我們從library到mouble,讓我們談談我理解的專案的Project架構。 lib-netwo

區塊鏈技術

關於區塊鏈技術的思考 自從比特幣成為全世界的焦點以後,區塊鏈莫名火了起來,無論是金融業還是網際網路企業都在盯著這一領域,各大高校也不甘落後,相繼開設區塊鏈課程和專案,就拿本人就讀的南京郵電大學而言,據我所知研究區塊鏈的專案組就能達到兩位數之多,但是事實上區塊鏈的

快取技術

Linux的Disk Cache 資料庫快取的重要性 Query Cache MySQL Query Cache監控工具 本教程由尚矽谷教育大資料研究院出品,如需轉載請註明來源。

android與javathis與activity.this

由於的java是草草的的過了一遍那樣學的 所以對很多概念已經是不太清楚了,這兩天開始看android 然後就發現很多東西有點看著懵逼 ,我是打算通過安卓去鞏固的java的 然後我看到了在活動中使用toast這裡 首先在此之前我的已經手動的寫了一個button的,那麼我希望說單擊butt

Android開發之垃圾回收機制GC以及如何用好GC

一、為什麼需要GC 應用程式對資源操作,通常簡單分為以下幾個步驟: 1、為對應的資源分配記憶體 2、初始化記憶體 3、使用資源 4、清理資源 5、釋放記憶體 應用程式對資源(記憶體使用)管理的方式,常見的一般有如下幾種: 1、手動管理:C,C++ 2、計數管理:COM 3、自動管理:.NET,Java,PH

網頁外掛技術(入門篇)

其實網頁外掛所用的技術很簡單,只不過這是一個技術上的禁區,極少有書籍和資料介紹而已。在繼續往下看之前,你至少需要了解:1.http協議的基本含義2.socket通訊基礎3.一門常規開發語言及軟體開發基礎4.動態網頁技術基礎網頁遊戲採用的通訊協議多種多樣,常見的有:1.純htt

Android學習之對MVC模式和MVP模式的理解

進來聽群裡大神們一直在講MVP模式的好處優點種種…,因為mvp出來有一段時間了,但是還沒怎麼了解過,所以週末看了看,並且敲了幾個demo,感覺有點心得了,就淺談一下自己的理解,不正確的地方請及時指出,謝謝! MVC模式: 邏輯:View通知Con

Android開發:MVP模式應用與記憶體洩漏

最近博主開始在專案中實踐MVP模式,卻意外發現記憶體洩漏比較嚴重,但卻很少人談到這個問題,促使了本文的釋出,本文假設讀者已瞭解MVP架構。 MVP簡介 M-Modle,資料,邏輯操作層,資料獲取,資料持久化儲存。比如網路操作,資料庫操作 V-Vie

JSP學習心得-程式設計師技術

下面是本人在學習JSP時的一些心得,特此奉獻出來以供大家分享。  一、JSP工作原理  在一個JSP檔案第一次被請求時,JSP引擎把該JSP檔案轉換成為一個servlet。而這個引擎本身也是一個servlet,在JSWDK或WEBLOGIC中,它就是JspServlet。 

Android 瀏覽器核心

 目前,移動裝置瀏覽器上常用的核心有Webkit,Blink,Trident,Gecko等,其中iPhone和iPad等蘋果iOS平臺主要是WebKit,Android 4.4之前的android系統瀏覽器核心是WebKit,Android4.4系統瀏覽器切換到了Chrom

Android dropbox日誌

Android4.4.2 Android dropbox提供了一種儲存日誌的機制,支援將核心、Native、Java多種日誌儲存在"/data/system/dropbox"目錄中。 兩個主要的類是DropBoxManager和IDropBoxManagerService

[Java][Android][Process] Process 創建+控制+分析 經驗

send 實現 亦或 想要 unable github stringbu data- 滿了 不管是Android亦或者Java中或多或少須要調用底層的一些命令。運行一些參數; 此時我們須要用到Java的Process來創建一個子進程。之所以是子進程是由於此進程依賴於發起

非法外聯檢測技術的演變

非法外聯 違規外聯 手機外聯 usb共享 無線熱點 電話撥號 針對隔離內網,非法外聯因其危害巨大,一直都是網絡邊界完整性防護的重中之重。早期非法外聯主要是指以電話撥號為主的私自連接互聯網的行為,早期電話撥號還是非常方便的,如163撥號,263撥號等,只要有電話線,就可以隨時撥號上網,缺

【轉】分布式服務協調技術 Zookeeper

客戶 內存數據 訂閱 數據開發 watcher database 所有 ren info 非常好介紹Zookeeper的文章, Google的三篇論文影響了很多很多人,也影響了很多很多系統。這三篇論文一直是分布式領域傳閱的經典。根據MapReduce,於是

360全景技術對會展的影響及應用

360全景 信息化的時代,一日千變,一個新的技術出現也許在幾秒內就能發生變化。這就是當今的信息速度。近年來360全景技術在中國廣泛運用,且在不斷的發展中。就360全景制作技術這一塊來說,360全景產業在國內外已取得了一定的收獲盈利模式也出現了多樣化,使得360全景產業呈現出欣欣向榮的景象。 會

車牌識別技術的應用

車牌識別技術的應用由來已久,車牌識別增加了車輛管理識別的速度,減少了擁堵,提高了大家的出行舒適度。對於在OCR識別技術領域有著十多年研發經驗的廈門雲脈來說,如何提高車牌識別的準確率,實現更精確的識別更是市場所需。 所以,雲脈自主研發推出的車牌識別技術,基於成熟的OCR技術,以計算機視覺處理、

Nginx服務器的安裝,升級、配置、LNMP平臺搭建、nginx+fastcgi、nginx高級技術-地址重寫及優化

perl 新的 大文件 文件的 add 並發連接數 文件配置 redirect ntp Nginx服務器:是俄羅斯人編寫的十分輕量級的HTTP服務器,是一個高性能的HTTP和反向代理服務器,同時也是一個IMAP/POP3/SMTP代理服務器 一、安裝Nginx軟件: 準備工

Android中的組播(多播)

-1 ip協議 strong 多個 接受 端口 ui線程 nbsp 數據 組播使用UDP對一定範圍內的地址發送相同的一組Packet,即一次可以向多個接受者發出信息,其與單播的主要區別是地址的形式。IP協議分配了一定範圍的地址空間給多播(多播只能使用這個範圍內