调用其他app 的lib_ButterKnife执行效率为什么比其他注入框架高?它的原理是什么...
面試官: ButterKnife為什么執(zhí)行效率為什么比其他注入框架高?它的原理是什么
心理分析: ButterKnife框架一直都是使用,很少又開(kāi)發(fā)者對(duì)butterknife深入研究的,既然你是面試Android高級(jí)崗位,自然需要有相應(yīng)被問(wèn)到原理的準(zhǔn)備,面試官想問(wèn)你對(duì)注解處理器了解多少,Android編譯流程有多少認(rèn)識(shí)
**求職者:**應(yīng)該從 注解處理器原理 與優(yōu)勢(shì)說(shuō)起,肯定注解處理器對(duì)解放生產(chǎn)力的作用。然后可以引申常見(jiàn)的 Butterknife,Dagger2,DBFlow。這才是加分項(xiàng)
優(yōu)勢(shì)
接下來(lái)我們一起來(lái)看注解處理的原理
在android開(kāi)發(fā)中,比較常用到的第三方庫(kù)中,有不少用到了 注解處理器(Annotation Processor)。 比較常見(jiàn)的就有 Butterknife,Dagger2,DBFlow 等。
注解
Java中存在不少關(guān)于注解的Api, 比如@Override用于覆蓋父類(lèi)方法,@Deprecated表示已舍棄的類(lèi)或方法屬性等,android中又多了一些注解的擴(kuò)展,如@NonNull, @StringRes, @IntRes等。
代碼自動(dòng)生成
使用代碼自動(dòng)生成,一是為了提高編碼的效率,二是避免在運(yùn)行期大量使用反射,通過(guò)在編譯期利用反射生成輔助類(lèi)和方法以供運(yùn)行時(shí)使用。
注解處理器的處理步驟主要有以下:
Butterknife注解處理器的例子
Butterknife的注解處理器的工作方式如下:
當(dāng)你點(diǎn)擊Android Studio的Build按鈕時(shí),Butterknife先是按照上述步驟生成了對(duì)應(yīng)的輔助類(lèi)和方法。在代碼執(zhí)行到bind(..)方法時(shí),Butterknife就去調(diào)用之前生成的輔助類(lèi)方法,完成對(duì)被注解元素的賦值操作。
自定義注解處理器
了解了基本的知識(shí)點(diǎn)后,我們應(yīng)該嘗試去使用這些技巧。 接下來(lái)是實(shí)踐時(shí)間,我們來(lái)開(kāi)發(fā)一個(gè)簡(jiǎn)單的例子,利用注解處理器來(lái)自動(dòng)產(chǎn)生隨機(jī)數(shù)字和隨機(jī)字符串。
1. 添加注解
在lib_annotations中添加兩個(gè)注解:RandomString, RandomInt,分別用于生成隨機(jī)數(shù)字和隨機(jī)字符串:
@Retention(CLASS)@Target(value = FIELD)public @interface RandomString {}復(fù)制代碼@Retention(CLASS)@Target(value = FIELD)public @interface RandomInt { int minValue() default 0; int maxValue() default 65535;}復(fù)制代碼- @interface 自定義注解,使用 @interface 作為類(lèi)名修飾符
- @Target 該注解所能修飾的元素類(lèi)型,可選類(lèi)型如下:
- @Retention 該注解的保留策略,有三種選項(xiàng):
2. 注解處理器
真正處理注解并生成代碼的操作都在這里。 在寫(xiě)代碼之前我們需要先導(dǎo)入兩個(gè)重要的庫(kù),以及我們的注解模塊:
compile 'com.google.auto.service:auto-service:1.0-rc4'compile 'com.squareup:javapoet:1.9.0'implementation project(':lib_annotations')復(fù)制代碼新建類(lèi)RandomProcessor.java:
@AutoService(Processor.class)public class RandomProcessor extends AbstractProcessor{ @Override public synchronized void init(ProcessingEnvironment processingEnvironment) { super.init(processingEnvironment); } @Override public SourceVersion getSupportedSourceVersion() { return super.getSupportedSourceVersion(); } @Override public Set getSupportedAnnotationTypes() { return super.getSupportedAnnotationTypes(); } @Override public boolean process(Set extends TypeElement> set, RoundEnvironment roundEnvironment) { return false; }}復(fù)制代碼- @AutoService @AutoService(Processor.class)會(huì)告訴編譯器該注解處理器的存在,并在編譯時(shí)自動(dòng)在META-INF/services下生成javax.annotation.processing.Processor文件,文件的內(nèi)容為
也就是說(shuō),你所聲明的注解處理器都會(huì)在被寫(xiě)入這個(gè)配置文件中。 這樣子,當(dāng)外部程序裝載這個(gè)模塊的時(shí)候,就能通過(guò)該模塊的jar包下的META-INF/services下找到具體的注解處理器的實(shí)現(xiàn)類(lèi)名,并加載實(shí)例化,完成模塊的注入。 注解處理器需要實(shí)現(xiàn)AbstractProcessor接口,并實(shí)現(xiàn)對(duì)應(yīng)的方法
- init() 可選 在該方法中可以獲取到processingEnvironment對(duì)象,借由該對(duì)象可以獲取到生成代碼的文件對(duì)象, debug輸出對(duì)象,以及一些相關(guān)工具類(lèi)
- getSupportedSourceVersion() 返回所支持的java版本,一般返回當(dāng)前所支持的最新java版本即可
- getSupportedAnnotationTypes() 你所需要處理的所有注解,該方法的返回值會(huì)被process()方法所接收
- process() 必須實(shí)現(xiàn) 掃描所有被注解的元素,并作處理,最后生成文件。該方法的返回值為boolean類(lèi)型,若返回true,則代表本次處理的注解已經(jīng)都被處理,不希望下一個(gè)注解處理器繼續(xù)處理,否則下一個(gè)注解處理器會(huì)繼續(xù)處理。
初始化
較詳細(xì)代碼如下:
private static final List> RANDOM_TYPES = Arrays.asList(RandomInt.class, RandomString.class);private Messager messager;private Types typesUtil;private Elements elementsUtil;private Filer filer;private TypeonProcess()per.init(processingEnv); messager = processingEnv.getMessager(); typesUtil = processingEnv.getTypeUtils(); elementsUtil = processingEnv.getElementUtils(); filer = processingEnv.getFiler();}@Overridepublic SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported();}@Overridepublic Set getSupportedAnnotationTypes() { Set annotations = new LinkedHashSet<>(); for (Class extends Annotation> annotation : RANDOM_TYPES) { annotations.add(annotation.getCanonicalName()); } return annotations;}復(fù)制代碼處理注解
在process()方法中執(zhí)行以下操作:
生成類(lèi)文件
將之前以注解所在類(lèi)為key的map遍歷,并以key值為分組生成類(lèi)文件。
for (Map.Entry entry : annotatedElementMap.entrySet()) { MethodSpec constructor = createConstructor(entry.getValue()); TypeSpec binder = createClass(getClassName(entry.getKey()), constructor); JavaFile javaFile = JavaFile.builder(getPackage(entry.getKey()), binder).build(); javaFile.writeTo(filer);}復(fù)制代碼生成類(lèi)、構(gòu)造函數(shù)、代碼段以及文件都是利用到了javapoet依賴(lài)庫(kù)。當(dāng)然你也可以選擇拼接字符串和自己用文件IO寫(xiě)入,但是用javapoet要更方便得多。
private MethodSpec createConstructor(List randomElements) { AnnotatedRandomElement firstElement = randomElements.get(0); MethodSpec.Builder builder = MethodSpec.constructorBuilder() .addModifiers(Modifier.PUBLIC) .addParameter(TypeName.get(firstElement.getElement().getEnclosingElement().asType()), "target"); for (int i = 0; i < randomElements.size(); i++) { addStatement(builder, randomElements.get(i)); } return builder.build();}private void addStatement(MethodSpec.Builder builder, AnnotatedRandomElement randomElement) { builder.addStatement(String.format( "target.%1$s = %2$s總結(jié)
以上是生活随笔為你收集整理的调用其他app 的lib_ButterKnife执行效率为什么比其他注入框架高?它的原理是什么...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: cmd小游戏_使用pygame制作Fla
- 下一篇: wap歌词原版 卡姐新歌wap原版歌词介