Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android Annotation注解學習筆記

Android Annotation注解學習筆記

編輯:關於Android編程

今天講下注解吧,現在遇到的用注解的開源庫越來越多,雖然知道怎麼用,但是其原理,怎麼寫都還不清楚。

注解的分類方式有很多:

標准的Annotation:override、deprecated、SuppressWarnings等(這些為Java自帶)。 元Annotation:這些注解是用來修飾注解的,例如Target(說明該注解是用來形容哪些程序元素的,例如Method、Field、Class等)、Retention(指明注解的生命周期,後面會詳述)、Documented(是否保存到Javadoc中)、Inherited(能否被繼承)。 其他Annotation:包括Android已經提供的Annotation(support-annotation包中)和自定義的Annotation。

當然還有其他的分類方式,根據注解的Retention來區分,剛剛說到Retention是注解的生命周期,那分為Source(源碼時注解)、Class(編譯時注解)、Runtime(運行時注解)。@Retention(RetentionPolicy.SOURCE)這個注解的意思是讓注解只在java源文件中存在,編譯成.class文件後注解就不存在了。@Retention(RetentionPolicy.CLASS)這個注解的意思是讓注解在java源文件(.java文件)中存在,編譯成.class文件後注解也還存在,被注解類標識的類被類加載器加載到內存中後MyAnnotation注解就不存在了。如果是Runtime的話,則加載到內存中,該注解還存在,下面是詳細解釋:

當在Java源程序上加了一個注解,這個Java源程序要由javac去編譯,javac把java源文件編譯成.class文件,在編譯成class時可能會把Java源程序上的一些注解給去掉,java編譯器(javac)在處理java源程序時,可能會認為這個注解沒有用了,於是就把這個注解去掉了,那麼此時在編譯好的class中就找不到注解了, 這是編譯器編譯java源程序時對注解進行處理的第一種可能情況,假設java編譯器在把java源程序編譯成class時,沒有把java源程序中的注解去掉,那麼此時在編譯好的class中就可以找到注解,當程序使用編譯好的class文件時,需要用類加載器把class文件加載到內存中,class文件中的東西不是字節碼,class文件裡面的東西由類加載器加載到內存中去,類加載器在加載class文件時,會對class文件裡面的東西進行處理,如安全檢查,處理完以後得到的最終在內存中的二進制的東西才是字節碼,類加載器在把class文件加載到內存中時也有轉換,轉換時是否把class文件中的注解保留下來,這也有說法,所以說一個注解的生命周期有三個階段:java源文件是一個階段,class文件是一個階段,內存中的字節碼是一個階段,javac把java源文件編譯成.class文件時,有可能去掉裡面的注解,類加載器把.class文件加載到內存時也有可能去掉裡面的注解,因此在自定義注解時就可以使用Retention注解指明自定義注解的生命周期,自定義注解的生命周期是在RetentionPolicy.SOURCE階段(java源文件階段),還是在RetentionPolicy.CLASS階段(class文件階段),或者是在RetentionPolicy.RUNTIME階段(內存中的字節碼運行時階段),根據JDK提供的API可以知道默認是在RetentionPolicy.CLASS階段 (JDK的API寫到:the retention policy defaults to RetentionPolicy.CLASS.)

如果是Source和Class的話,即使引起Android Studio報錯,也不會影響運行,依舊可以運行。舉個簡單的例子,EventBus庫(最新的版本onEvent函數使用了@Subscribe注解),我們知道其原理是當對象注冊了EventBus後,EventBus會記錄該類onEvent方法,當檢測到有消息post出來後,會調用有subscribe注解的方法,試想一下,如果這歌subscribe是source或者class的話,那麼加載到內存的時候,就已經沒有了,那麼Eventbus找不到任何方法來處理事件,所以subscribe一定是運行時,看下代碼:

package org.greenrobot.eventbus;


import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
    ThreadMode threadMode() default ThreadMode.POSTING;

    /**
     * If true, delivers the most recent sticky event (posted with
     * {@link EventBus#postSticky(Object)}) to this subscriber (if event available).
     */
    boolean sticky() default false;

    /** Subscriber priority to influence the order of event delivery.
     * Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before
     * others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of
     * delivery among subscribers with different {@link ThreadMode}s! */
    int priority() default 0;
}

果然沒錯,驗證了我們的猜想。

安卓中的注解分為八大類:

Nullness注解:@Nullable、@NoNull(為方法的形參加上這個,可以減少判空的代碼) 資源類型注解:以Res結尾,例如@StringRes、@ColorRes、@IdRes等 權限注解:@requestPermission,這個注解在PermissionDispatcher這個開源庫中用到 CallSuper注解:被@CallSuper修飾的方法,一定要調用super方法 枚舉注解:@IntDef和@StringDef,具體用法可以看Toast下Duration 線程注解:@MainThread、@WorkThread等,被這些注解修飾的方法只能在該線程內調用 變量限制注解:@Size、@IntRange、@FloatRange等 結果檢查注解:@CheckResult,被該注解修飾的方法,需要對方法的返回值進行處理。例如Context.checkPermission(@NonNull String permission, int pid, int uid)方法,防止別人誤解該方法就已經算是請求權限了,調用該方法一定要判斷返回值,權限是否被賦予,如果不判斷,調用該方法無用。如果只是簡單調該函數,並未判斷返回值,則會提示是否使用另外一個函數。
@CheckResult(suggest="#enforcePermission(String,int,int,String)")
@PackageManager.PermissionResult
public abstract int checkPermission(@NonNull String permission, int pid, int uid);

講到現在都還沒舉一個具體的例子,那就讓我們來看看常見的ColorRes:

@Documented
@Retention(CLASS)
@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
public @interface ColorRes {
}

解釋下上述代碼:該注解將會保存到Javadoc中;該注解是編譯時注解,在class文件中還會存在,但是在內存中就沒了;該注解用來修飾方法、參數、屬性、局部變量。
還有一些比較好用的注解,例如@Keep,該注解表示被該注解修飾的元素將不會被混淆。

下面講下編譯時解析:由apt(Annotation Processing Tool)自動解析

自定義類繼承自AbstractProcessor 重寫該類的Process函數
apt在編譯時自動查找所有繼承自AbstractProcessor的類,調用process函數去處理。
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved