国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

自定義Android注解Part1:注解變量

KavenFan / 2574人閱讀

摘要:下面我們會自己實現與注解,實現中的對應注解功能。帶大家一起來聲明注解變量。知道了它的作用范圍之后,我們在自定義注解時就要盡量較小注解的作用范圍,提高項目的編譯與運行速度。它們代表自定義的注解能夠作用的對象。總結庫中的自定義注解就完成了。

對于Android注解,或多或少都有一點接觸,但相信大多數人都是在使用其它依賴庫的時候接觸的。因為有些庫如果你想使用它就必須使用它所提供的注解。例如:ButterKnife、Dagger2、Room等等。

至于為何使用注解?使用過的應該都知道,最明顯的就是方便、簡潔。通過使用注解可以在項目編譯階段,幫助我們自動生成一些重復的代碼,減輕我們的負擔。典型的ButterKnife本質就是使用Android注解,通過注解來減少我們對view.findViewById的編寫,提高我們的開發效率。上一個系列(AAC)的Room也是一樣,我們可以簡單的回顧一下:

@Entity(tableName = "contacts")
data class ContactsModel(
        @PrimaryKey
        @ColumnInfo(name = "contacts_id")
        val id: Int,
        @ColumnInfo(name = "name")
        val name: String,
        @ColumnInfo(name = "phone")
        val phone: String
)

通過使用注解來定義一個實體表,也就10行左右的代碼。如果要我們全部自己寫那絕對要兩三百行代碼了,而且其中還可能出錯,又要改bug等等。效率就嚴重降低。對于依賴庫如果都這么麻煩也就不會有人用了。

那么如何判斷一個依賴庫是否需要使用注解呢?其實很簡單,只要記住以下兩點即可:

需要生成的代碼不能與項目邏輯有關

Android注解只能生成代碼,并不能修改代碼

這里透露一下,Android注解的本質是使用Java的反射機制,后續會詳細說明
項目架構

相信ButterKnife應該有接觸過吧,沒有的也沒關系,現在正是時候。下面我們會自己實現BindView與OnClick注解,實現ButterKnife中的對應注解功能。那么我先來看下整體的項目架構

通過項目圖,我們可以清晰的看到,主要分為三個部分

butterknife-annotations:注解庫,包含BindView與OnClick等自定義的注解

butterknife-bind:綁定庫,自定義的注解與聲明的類綁定

butterknife-compiler: 解析編譯生成庫,解析聲明類中的注解,在編譯時自動生成相應的代碼。

為了幫助大家能夠更輕松的理解Android注解,今天主要分析的就是butterknife-annotations這個注解庫。帶大家一起來聲明注解變量。

BindView

為了要實現開源庫butterknife類似的綁定id效果,這里我們先定義一個BindView注解,具體如下:

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.FIELD)
public @interface BindView {
    @IdRes int[] value();
}

嗯,還是很簡單的對吧。也就5行代碼解決BindView注解的定義。

那么再來詳細剖析這5行代碼。

Retention

首先是第一行代碼的Retention,看它的使用方式就能知道,它也是一個聲明了的注解。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}

通過源碼我們可以看出該注解只接收一個參數,該參數為RetentionPolicy類型。那么我們在進一步深入RetentionPolicy:

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,
 
    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS,
 
    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}

在這里我們發現它其實是一個枚舉,在枚舉中支持三個常量,分別為SOURCE、CLASS與RUNTIME。它們的區別主要是作用的周期范圍,下面我再對這三個的作用進行翻譯一遍:

SOURCE: 使用該標明的注解將在編譯階段就被拋棄掉。

CLASS:使用該標明的注解將在編譯階段記錄到生成的class文件中,但在運行階段時又會被VM拋棄。默認是該模式。

RUNTIME:使用該標明的注解將在編譯階段被保存在生成的class文件中,同時在運行階段時會保存到VM中。所以它該注解將一直存在,自然能夠通過java的反射機制進行讀取。

所以它們的存在的生命時長為SOURCE < CLASS < RUNTIME。知道了它的作用范圍之后,我們在自定義注解時就要盡量較小注解的作用范圍,提高項目的編譯與運行速度。

因為我們的BindView注解只是為了進行Viwe的綁定,所以在編譯之后就無需存在,所以這里就使用了CLASS來進行標明。

Target

下面我們在來看第二行代碼,這里使用到了另一個注解Target,我們還是來看下它的源碼:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * Returns an array of the kinds of elements an annotation type
     * can be applied to.
     * @return an array of the kinds of elements an annotation type
     * can be applied to
     */
    ElementType[] value();
}

可以看到注解的源碼都非常簡單,這里接收了一個ElementType數組參數,ElementType不難猜出它的類型也是一個枚舉:

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,
 
    /** Field declaration (includes enum constants) */
    FIELD,
 
    /** Method declaration */
    METHOD,
 
    /** Formal parameter declaration */
    PARAMETER,
 
    /** Constructor declaration */
    CONSTRUCTOR,
 
    /** Local variable declaration */
    LOCAL_VARIABLE,
 
    /** Annotation type declaration */
    ANNOTATION_TYPE,
 
    /** Package declaration */
    PACKAGE,
 
    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,
 
    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}

ElementType中雖然有10常量,但我們實際真正常用的也就是前面8種。它們代表自定義的注解能夠作用的對象。分別為:

TYPE: 作用于類、接口或者枚舉

FIELD:作用于類中聲明的字段或者枚舉中的常量

METHOD:作用于方法的聲明語句中

PARAMETER:作用于參數聲明語句中

CONSTRUCTOR:作用于構造函數的聲明語句中

LOCAL_VARIABLE:作用于局部變量的聲明語句中

ANNOTATION_TYPE:作用于注解的聲明語句中

PACKAGE:作用于包的聲明語句中

TYPE_PARAMETER:java 1.8之后,作用于類型聲明的語句中

TYPE_USE:java 1.8之后,作用于使用類型的任意語句中

結合我們的BindView的作用是對View進行id綁定,自然是作用與聲明的字段上。所以在BindView中使用了FIELD。

再來看第四行代碼

@IdRes int[] value()

有了上面的注解接觸,不難理解這是標明BindView將接收一個int類型的數組參數。對于開源庫butterknife中的BindView是接收需要綁定的View的id,這里我們做一個改版,再接收一個String的id,用來為綁定的View設置默認值。這樣我們自定義了的BindView注釋就完成了。

OnClick

下面我們再自定義一個OnClick點擊的注解,經過上面的分析,可以在腦海中想想Retention與Target分別什么值?

想好了之后我們在來過一遍

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
public @interface OnClick {
    @IdRes int value();
}

Retention的作用范圍與BindView一樣首頁SOURCE,在編譯之后就無需存在;Target的作用對象與BindView不同,既然是點擊事件的點擊操作,自然是作用在操作邏輯的方法上,所以這里使用METHOD。

keep

文章開頭有提及到本質是通過注解來自動生成代碼,為我們創建所需的類,那么在實際開發中一旦我們的項目混淆了,這將會導致自動創建的類失效,從而導致我們自定義的注解失效。所以為了防止其失效,我們在這里再定義一個注解keep:

@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface Keep {
}

Retention的作用范圍是在class文件中還要能夠被其它class調用,所以這里使用CLASS;Target作用對象是自動生成的類,所以使用TYPE。至于參數則不必要,它只是為了標明類,防止其被混淆。

總結

butterknife-annotations庫中的自定義注解就完成了。通過上面的分析,我們注意點主要歸結于以下三點:

Retention: 明確注解作用的生命時長,盡早的消除

Target: 明確注解作用的對象

Keep: 防止后續自動生成的類被混淆

注解變量的定義就到這結束了,同時文章中的代碼都可以在Github中獲取到。使用時請將分支切換到feat_annotation_processing

如果感覺不錯的話,可以點贊收藏哦,這是對我最大的支持,謝謝!

相關文章

自定義Android注解Part2:代碼自動生成

自定義Android注解Part3:綁定

關注

私人博客

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/71463.html

相關文章

  • 定義Android注解Part3:綁定

    摘要:上一節我們已經將自動生成注解代碼部分介紹完畢,今天這篇文章是自定義注解系列的最后一篇文章。該部分是對我們前面定義的注解變量與自動生成的代碼進行綁定,即調用我們自動生成的代碼。 showImg(https://segmentfault.com/img/bVbdEsh?w=1200&h=720); 上一節我們已經將自動生成注解代碼部分介紹完畢,今天這篇文章是自定義Android注解系列的最...

    王晗 評論0 收藏0
  • 5分鐘吃透React Native Flexbox

    摘要:在中是主流布局方式。它有三種狀態正數零與負數。來看下運行效果。這是為正數的情況,如果,控件的大小就會根據設置的與來固定顯示。如果發現生效的方式請務必告知。在中有主軸與副軸之分,主軸控制的排列方向,默認為。默認值為,繼承父容器的屬性。 今天我們來聊聊Flexbox,它是前端的一個布局方式。在React Native中是主流布局方式。如果你剛剛入門React Native,或者沒有多少前端...

    developerworks 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<