日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > Android >内容正文

Android

【Android APT】编译时技术 ( ButterKnife 原理分析 )

發(fā)布時(shí)間:2025/6/17 Android 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Android APT】编译时技术 ( ButterKnife 原理分析 ) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 一、編譯時(shí)技術(shù)簡(jiǎn)介
  • 二、ButterKnife 原理分析
  • 二、ButterKnife 生成 Activity_ViewBinding 代碼分析





一、編譯時(shí)技術(shù)簡(jiǎn)介



APT ( Annotation Processing Tool ) 注解處理工具 ;


編譯時(shí)技術(shù) , 廣泛應(yīng)用在當(dāng)前主流框架中 , 如 JetPack 中的 DataBinding , Room , Navigatoion , 第三方 ButterKnife , ARouter 等框架 ;


編譯時(shí)技術(shù) 最重要的作用就是在編譯時(shí)可以 生成模板代碼 ;

由于生成代碼操作是在編譯時(shí)進(jìn)行的 , 不會(huì)對(duì)運(yùn)行時(shí)的性能產(chǎn)生影響 ;


程序的周期 :

源碼期 : 開(kāi)發(fā)時(shí) , 剛編寫(xiě)完 " .java " 代碼 , 還未編譯之前 , 就處于源碼期 ;

編譯期 : 程序由 java 源碼編譯成 class 字節(jié)碼文件 ;

運(yùn)行期 : 將字節(jié)碼文件加載到 Java 虛擬機(jī)中運(yùn)行 ;


編譯時(shí)技術(shù) APT 作用于 編譯期 , 在這個(gè)過(guò)程中使用該技術(shù) , 生成代碼 ;


編譯時(shí)技術(shù) 222 大核心要素 : 在編譯時(shí) , 執(zhí)行生成代碼的邏輯 , 涉及到兩個(gè)重要概念 ;

① 編譯時(shí)注解 ;

② 注解處理器 ;


舉例說(shuō)明 : 使用 ButterKnife 時(shí)會(huì)依賴兩個(gè)庫(kù) ,

dependencies {implementation 'com.jakewharton:butterknife:10.2.3'annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.3' }

其中 com.jakewharton:butterknife:10.2.3 是 編譯時(shí)注解 , com.jakewharton:butterknife-compiler:10.2.3 是 注解處理器 ;





二、ButterKnife 原理分析



使用 ButterKnife :

① 添加依賴 :

dependencies {implementation 'com.jakewharton:butterknife:10.2.3'annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.3' }

② Activity 中使用 ButterKnife :

package kim.hsl.apt;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle; import android.widget.TextView;import butterknife.BindView; import butterknife.ButterKnife;public class MainActivity extends AppCompatActivity {@BindView(R.id.hello)TextView hello;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ButterKnife.bind(this);hello.setText("ButterKnife");} }

BindView 注解分析 : 在 TextView hello 成員變量處添加了 @BindView(R.id.hello) 注解 ;

@Target(FIELD) 元注解 : 表示其作用與類的成員字段 ;

@Retention(RUNTIME) 元注解 : 表示該注解保留到運(yùn)行時(shí)階段 ;

int value() 注解屬性 : 只有一個(gè)注解屬性 , 并且屬性名是 value , 則使用注解時(shí) “value =” 可省略 ;

@Retention(RUNTIME) @Target(FIELD) public @interface BindView {/** View ID to which the field will be bound. */@IdRes int value(); }

TextView hello 需要使用 findViewById 進(jìn)行賦值 , 在上述代碼中沒(méi)有寫(xiě) findViewById 相關(guān)的代碼 ; 肯定是在某個(gè)地方執(zhí)行了 findViewById 的方法 ;

ButterKnife.bind(this) 代碼就是執(zhí)行了 findViewById 方法 ;


ButterKnife 用到了編譯時(shí)技術(shù)會(huì) , 在項(xiàng)目編譯時(shí) , 會(huì)生成 MainActivity_ViewBinding 類 , 在該類中 , 會(huì)查找添加了 @BindView 直接的成員變量 , 再獲取 注解屬性 value 的值 , 然后調(diào)用 findViewById 方法獲取組件并為成員變量賦值 ;

// Generated code from Butter Knife. Do not modify! package kim.hsl.apt;import android.view.View; import android.widget.TextView; import androidx.annotation.CallSuper; import androidx.annotation.UiThread; import butterknife.Unbinder; import butterknife.internal.Utils; import java.lang.IllegalStateException; import java.lang.Override;public class MainActivity_ViewBinding implements Unbinder {private MainActivity target;@UiThreadpublic MainActivity_ViewBinding(MainActivity target) {this(target, target.getWindow().getDecorView());}@UiThreadpublic MainActivity_ViewBinding(MainActivity target, View source) {this.target = target;target.hello = Utils.findRequiredViewAsType(source, R.id.hello, "field 'hello'", TextView.class);}@Override@CallSuperpublic void unbind() {MainActivity target = this.target;if (target == null) throw new IllegalStateException("Bindings already cleared.");this.target = null;target.hello = null;} }



二、ButterKnife 生成 Activity_ViewBinding 代碼分析



調(diào)用 ButterKnife 靜態(tài)方法 Unbinder bind(@NonNull Activity target) , 傳入 Activity 對(duì)象 , 在方法中調(diào)用了 ButterKnife 的 bind 方法 ;


bind 方法中 , 先獲取了 Activity 的類對(duì)象 ,

Class<?> targetClass = target.getClass();

然后將類對(duì)象傳入了 findBindingConstructorForClass 方法 ,

Constructor<? extends Unbinder> constructor = findBindingConstructorForClass(targetClass);

findBindingConstructorForClass 方法中 , 獲取了某個(gè)構(gòu)造方法 ,

Constructor<? extends Unbinder> bindingCtor = BINDINGS.get(cls);

獲取 Activity 類對(duì)象名稱 , 即 " kim.hsl.apt.MainActivity " ,

String clsName = cls.getName();

得到名稱后 , 判斷該類對(duì)象是否是系統(tǒng)的 API , 如果是則退出 ; 如果不是 , 則繼續(xù)向下執(zhí)行 ,

if (clsName.startsWith("android.") || clsName.startsWith("java.")|| clsName.startsWith("androidx.")) {if (debug) Log.d(TAG, "MISS: Reached framework class. Abandoning search.");return null; }

拼裝要生成的類名稱 , “kim.hsl.apt.MainActivity_ViewBinding” , 并自動(dòng)生成該類 ;

Class<?> bindingClass = cls.getClassLoader().loadClass(clsName + "_ViewBinding");

ButterKnife 涉及到的源碼 :

public final class ButterKnife {/*** BindView annotated fields and methods in the specified {@link Activity}. The current content* view is used as the view root.** @param target Target activity for view binding.*/@NonNull @UiThreadpublic static Unbinder bind(@NonNull Activity target) {View sourceView = target.getWindow().getDecorView();return bind(target, sourceView);}/*** BindView annotated fields and methods in the specified {@code target} using the {@code source}* {@link View} as the view root.** @param target Target class for view binding.* @param source View root on which IDs will be looked up.*/@NonNull @UiThreadpublic static Unbinder bind(@NonNull Object target, @NonNull View source) {Class<?> targetClass = target.getClass();if (debug) Log.d(TAG, "Looking up binding for " + targetClass.getName());Constructor<? extends Unbinder> constructor = findBindingConstructorForClass(targetClass);if (constructor == null) {return Unbinder.EMPTY;}//noinspection TryWithIdenticalCatches Resolves to API 19+ only type.try {return constructor.newInstance(target, source);} catch (IllegalAccessException e) {throw new RuntimeException("Unable to invoke " + constructor, e);} catch (InstantiationException e) {throw new RuntimeException("Unable to invoke " + constructor, e);} catch (InvocationTargetException e) {Throwable cause = e.getCause();if (cause instanceof RuntimeException) {throw (RuntimeException) cause;}if (cause instanceof Error) {throw (Error) cause;}throw new RuntimeException("Unable to create binding instance.", cause);}}@Nullable @CheckResult @UiThreadprivate static Constructor<? extends Unbinder> findBindingConstructorForClass(Class<?> cls) {Constructor<? extends Unbinder> bindingCtor = BINDINGS.get(cls);if (bindingCtor != null || BINDINGS.containsKey(cls)) {if (debug) Log.d(TAG, "HIT: Cached in binding map.");return bindingCtor;}String clsName = cls.getName();if (clsName.startsWith("android.") || clsName.startsWith("java.")|| clsName.startsWith("androidx.")) {if (debug) Log.d(TAG, "MISS: Reached framework class. Abandoning search.");return null;}try {Class<?> bindingClass = cls.getClassLoader().loadClass(clsName + "_ViewBinding");//noinspection uncheckedbindingCtor = (Constructor<? extends Unbinder>) bindingClass.getConstructor(cls, View.class);if (debug) Log.d(TAG, "HIT: Loaded binding class and constructor.");} catch (ClassNotFoundException e) {if (debug) Log.d(TAG, "Not found. Trying superclass " + cls.getSuperclass().getName());bindingCtor = findBindingConstructorForClass(cls.getSuperclass());} catch (NoSuchMethodException e) {throw new RuntimeException("Unable to find binding constructor for " + clsName, e);}BINDINGS.put(cls, bindingCtor);return bindingCtor;} }

總結(jié)

以上是生活随笔為你收集整理的【Android APT】编译时技术 ( ButterKnife 原理分析 )的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。