深入學習-Gradle-自動化構建技術(六,騰訊安卓面試

mb612e2bd2b528b 2021-09-18 06:06:39 阅读数:188

深入 gradle- gradle

收集相關的 Stream API 與其實例代碼如下所示:

  • 1)、toList List 把流中元素收集到 List:
List<Person> emps= list.stream().collect(Collectors.toList());

  • 1.
  • 2)、toSet Set 把流中元素收集 到Set:
Set<Person> emps= list.stream().collect(Collectors.toSet());

  • 1.
  • 3)、toCollection Collection 把流中元素收集到創建的集合:
Collection<Person> emps=list.stream().collect(Collectors.toCollection(ArrayList::new));

  • 1.
  • 4)、counting Long 計算流中元素的個數:
long count = list.stream().collect(Collectors.counting());

  • 1.
  • 5)、summing Int Integer 對流中元素的整數屬性求和:
int total=list.stream().collect(Collectors.summingInt(Person::getAge));

  • 1.
  • 6)、averaging Int Double 計算流中元素 Integer 屬性的平均值:
double avg= list.stream().collect(Collectors.averagingInt(Person::getAge));

  • 1.
  • 7)、summarizingInt IntSummaryStatistics 收集流中 Integer 屬性的統計值。如平均值:
Int SummaryStatisticsiss= list.stream().collect(Collectors.summarizingInt(Person::getAge));

  • 1.
  • 8)、joining String 連接流中每個字符串:
String str= list.stream().map(Person::getName).collect(Collectors.joining());

  • 1.
  • 9)、maxBy Optional 根據比較器選擇最大值:
Optional<Person> max= list.stream().collect(Collectors.maxBy(comparingInt(Person::getSalary)));

  • 1.
  • 10)、minBy Optional 根據比較器選擇最小值:
Optional<Person> min = list.stream().collect(Collectors.minBy(comparingInt(Person::getSalary)));

  • 1.
  • 11)、reducing 歸約產生的類型,從一個作為累加器的初始值開始,利用 BinaryOperator 與流中元素逐個結合,從而歸約成單個值:
int total=list.stream().collect(Collectors.reducing(0, Person::getSalary, Integer::sum));

  • 1.
  • 12)、collectingAndThen 轉換函數返回的類型,包裹另一個收集器,對其結果轉換函數
int how= list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size));

  • 1.
  • 13)、groupingBy Map<K, List> 根據某屬性值對流分組,屬性為 K,結果為 V:
Map<Person.Status, List<Person>> map= list.stream().collect(Collectors.groupingBy(Person::getStatus));

  • 1.
  • 14)、partitioningBy Map<Boolean, List> 根 據true 或 false 進行分區:
Map<Boolean,List<Person>>vd= list.stream().collect(Collectors.partitioningBy(Person::getManage));

  • 1.
4、終止操作練習案例
  • 1)、取出Person對象的所有名字,放到 List 集合中:
List<String> collect2 = persons.stream().map(Person::getName).collect(Collectors.toList());

  • 1.
  • 2、求 Person 對象集合的分數的平均分、總分、最高分,最低分,分數的個數:
IntSummaryStatistics collect = persons.stream().collect(Collectors.summarizingInt(Person::getScore));
System.out.println(collect);

  • 1.
  • 2.
  • 3、根據成績分組,及格的放一組,不及格的放另外一組:
Map<Boolean, List<Person>> collect1 = persons.stream().collect(Collectors.partitioningBy(person -> person.getScore() >= 60));
System.out.println(collect1);

  • 1.
  • 2.
  • 4、統計 aa.txt 裏面的單詞數:
public static void main(String[] args) throws IOException {
InputStream resourceAsStream = Person.class.getClassLoader().getResourceAsStream("aa.txt");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(resourceAsStream));
bufferedReader.lines().flatMap(x->Stream.of(x.split(" "))).sorted().collect(Collectors.groupingBy(String::toString)).forEach((a,b)-> System.out.println(a+":"+b.size()));
bufferedReader.close();
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

4、複雜泛型

1)、泛型是什麼?

泛型,即 「“參數化類型”」。就是將類型由原來的具體的類型參數化,類似於方法中的變量參數,此時類型也定義成參數形式(可以稱之為類型形參),然後在使用/調用時傳入具體的類型(類型實參)。

2)、泛型的好處

  • 「適用於多種數據類型執行相同的代碼」
  • 「泛型中的類型在使用時指定,不需要强制類型轉換」

3)、泛型類和泛型接口

泛型的本質是為了參數化類型(在不創建新的類型的情况下,通過泛型指定的不同類型來控制形參具體限制的類型)。而這種參數類型可以用在類、接口和方法中,分別被稱為 「泛型類、泛型接口、泛型方法」

泛型類

引入一個類型變量T(其他大寫字母都可以,不過常用的就是T,E,K,V等等),並且用<>括起來,並放在類名的後面。「泛型類是允許有多個類型變量的」。常見的示例代碼如下所示:

public class NormalGeneric<K> {
private K data;
public NormalGeneric() {
}
public NormalGeneric(K data) {
this.data = data;
}
public K getData() {
return data;
}
public void setData(K data) {
this.data = data;
}
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
public class NormalGeneric2<T,K> {
private T data;
private K result;
public NormalGeneric2() {
}
public NormalGeneric2(T data) {
this();
this.data = data;
}
public NormalGeneric2(T data, K result) {
this.data = data;
this.result = result;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public K getResult() {
return result;
}
public void setResult(K result) {
this.result = result;
}
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.

泛型接口

泛型接口與泛型類的定義基本相同。示例代碼如下所示:

public interface Genertor<T> {
public T next();
}

  • 1.
  • 2.
  • 3.

但是,「實現泛型接口的類,有兩種實現方法」

1、未傳入泛型實參

在 new 出類的實例時,需要指定具體類型:

public class ImplGenertor<T> implements Genertor<T> {
@Override
public T next() {
return null;
}
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
2、傳入泛型實參

在 new 出類的實例時,和普通的類沒區別。

public class ImplGenertor2 implements Genertor<String> {
@Override
public String next() {
return null;
}
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

泛型方法

泛型方法的 定義在 「修飾符與返回值」 的中間。示例代碼如下所示:

public <T> T genericMethod(T...a){
return a[a.length/2];
}

  • 1.
  • 2.
  • 3.

泛型方法,是在調用方法的時候指明泛型的具體類型,泛型方法可以在任何地方和任何場景中使用,包括普通類和泛型類。

泛型類中定義的普通方法和泛型方法的區別

在普通方法中:

// 雖然在方法中使用了泛型,但是這並不是一個泛型方法。
// 這只是類中一個普通的成員方法,只不過他的返回值是在聲明泛型類已經聲明過的泛型。
// 所以在這個方法中才可以繼續使用 T 這個泛型。
public T getKey(){
return key;
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

在泛型方法中:

/**
* 這才是一個真正的泛型方法。
* 首先在 public 與返回值之間的 <T> 必不可少,這錶明這是一個泛型方法,並且聲明了一個泛型 T
* 這個 T 可以出現在這個泛型方法的任意比特置,泛型的數量也可以為任意多個。
*/
public <T,K> K showKeyName(Generic<T> container){
// ...
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

4)、限定類型變量

public class ClassBorder<T extends Comparable> {
...
}
public class GenericRaw<T extends ArrayList&Comparable> {
...
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

-<T extends Comparable>「T 錶示應該綁定類型的子類型,Comparable 錶示綁定類型,子類型和綁定類型可以是類也可以是接口」

  • 「extends 左右都允許有多個,如 T,V extends Comparable&Serializable」
  • 「注意限定類型中,只允許有一個類,而且如果有類,這個類必須是限定列錶的第一個」
  • 「限定類型變量既可以用在泛型方法上也可以用在泛型類上」

5)、泛型中的約束和局限性

  • 1、不能用基本類型實例化類型參數。
  • 2、運行時類型查詢只適用於原始類型。
  • 3、泛型類的靜態上下文中類型變量失效:不能在靜態域或方法中引用類型變量。因為泛型是要在對象創建的時候才知道是什麼類型的,而對象創建的代碼執行先後順序是 static 的部分,然後才是構造函數等等。所以在對象初始化之前 static 的部分已經執行了,如果你在靜態部分引用泛型,那麼毫無疑問虛擬機根本不知道是什麼東西,因為這個時候類還沒有初始化。
  • 4、不能創建參數化類型的數組,但是可以定義參數化類型的數組。
  • 5、不能實例化類型變量。
  • 6、不能使用 try-catch 捕獲泛型類的實例。

6)、泛型類型的繼承規則

泛型類可以繼承或者擴展其他泛型類,比如 List 和 ArrayList:

private static class ExtendPair<T> extends Pair<T>{
...
}

  • 1.
  • 2.
  • 3.

7)、通配符類型

  • ?extends X「錶示類型的上界,類型參數是 X 的子類」
  • ?super X「錶示類型的下界,類型參數是 X 的超類」

?extends X

如果其中提供了 get 和 set 類型參數變量的方法的話,set 方法是不允許被調用的,會出現編譯錯誤,而 get 方法則沒問題。

?extends X 錶示類型的上界,類型參數是 X 的子類,那麼可以肯定的說,get 方法返回的一定是個 X(不管是 X 或者 X 的子類)編譯器是可以確定知道的。但是 set 方法只知道傳入的是個 X,至於具體是 X 的哪個子類,是不知道的。

因此,「?extends X 主要用於安全地訪問數據,可以訪問 X 及其子類型,並且不能寫入非 null 的數據」

?super X

如果其中提供了 get 和 set 類型參數變量的方法的話,set 方法可以被調用,且能傳入的參數只能是 X 或者 X 的子類。而 get 方法只會返回一個 Object 類型的值。

? super X 錶示類型的下界,類型參數是 X 的超類(包括 X 本身),那麼可以肯定的說,get 方法返回的一定是個 X 的超類,那麼到底是哪個超類?不知道,但是可以肯定的說,Object 一定是它的超類,所以 get 方法返回 Object。編譯器是可以確定知道的。對於 set 方法來說,編譯器不知道它需要的確切類型,但是 X 和 X 的子類可以安全的轉型為 X。

因此,「?super X 主要用於安全地寫入數據,可以寫入 X 及其子類型」

無限定的通配符 ?

「錶示對類型沒有什麼限制,可以把 ?看成所有類型的父類,如 ArrayList<?>」

8)、虛擬機是如何實現泛型的?

泛型思想早在 C++ 語言的模板(Template)中就開始生根發芽,「在 Java 語言處於還沒有出現泛型的版本時,只能通過 Object 是所有類型的父類和類型强制轉換兩個特點的配合來實現類型泛化」

由於 Java 語言裏面所有的類型都繼承於 java.lang.Object,所以 Object 轉型成任何對象都是有可能的。但是也因為有無限的可能性,就只有程序員和運行期的虛擬機才知道這個 Object 到底是個什麼類型的對象。在編譯期間,編譯器無法檢查這個 Object 的强制轉型是否成功,如果僅僅依賴程序員去保障這項操作的正確性,許多 ClassCastException 的風險就會轉嫁到程序運行期之中。

此外,泛型技術在 C#/C++ 和 Java 之中的使用方式看似相同,但實現上卻有著根本性的分歧,C# 裏面的泛型無論在程序源碼中、編譯後的 IL 中(Intermediate Language,中間語言,這時候泛型是一個占比特符),或是運行期的 CLR 中,都是切實存在的,「List<int> 與 List<String> 就是兩個不同的類型,它們在系統運行期生成,有自己的虛方法錶和類型數據,這種實現稱為類型膨脹,基於這種方法實現的泛型稱為真實泛型」

「Java 語言中的泛型則不一樣,它只在程序源碼中存在,在編譯後的字節碼文件中,就已經替換為原來的原生類型(Raw Type,也稱為裸類型)了,並且在相應的地方插入了强制轉型代碼」,因此,對於運行期的 Java 語言來說,ArrayList<int> 與 ArrayList<String> 就是同一個類,所以 「泛型技術實際上是 Java 語言的一顆語法糖,Java 語言中的泛型實現方法稱為類型擦除,基於這種方法實現的泛型稱為偽泛型」。 將一段 Java 代碼編譯成 Class 文件,然後再用字節碼反編譯工具進行反編譯後,將會發現泛型都不見了,程序又變回了 Java 泛型出現之前的寫法,泛型類型都變回了原生類型。

由於 Java 泛型的引入,各種場景(虛擬機解析、反射等)下的方法調用都可能對原有的基礎產生影響和新的需求,如在泛型類中如何獲取傳入的參數化類型等。因此,JCP 組織對虛擬機規範做出了相應的修改,引入了諸如 Signature、LocalVariableTypeTable 等新的屬性用於解决伴隨泛型而來的參數類型的識別問題,「Signature 是其中最重要的一項屬性,它的作用就是存儲一個方法在字節碼層面的特征簽名,這個屬性中保存的參數類型並不是原生類型,而是包括了參數化類型的信息」。修改後的虛擬機規範要求所有能識別 49.0 以上版本的 Class 文件的虛擬機都要能正確地識別 Signature 參數。

最後,「從 Signature 屬性的出現我們還可以得出結論,擦除法所謂的擦除,僅僅是對方法的 Code 屬性中的字節碼進行擦除,實際上元數據中還是保留了泛型信息,這也是我們能通過反射手段取得參數化類型的根本依據」

二、初識 ByteX

ByteX 使用了純 Java 來編寫源碼,它是一個基於 Gradle transform api 和 ASM 的字節碼插樁平臺。

?

調試:gradle clean :example:assembleRelease -Dorg.gradle.debug=true --no-daemon

?

1、優勢

  • 1)、「自動集成到其它宿主和插件一起整合為一個單獨的 MainTransformFlow,結合 class 文件多線程並發處理,避免了打包的額外時間呈線性增長」
  • 2)、「插件、宿主之間完全解耦,便於協同開發」
  • 3)、「common module 提供通用的代碼複用,每個插件只需專注自身的字節碼插樁邏輯」

2、MainTransformFlow 基本流程

在 MainTransformFlow implements MainProcessHandler 常規處理過程,會遍曆兩次工程構建中的所有 class。

  • 1)、第一次,遍曆 traverse 與 traverseAndroidJar 過程,以形成完整的類圖。
  • 2)、第二次,執行 transform:再遍曆一次工程中所有的構建產物,並對 class 文件做處理後輸出。

3、如何自定義獨立的 TransformFlow?

重寫 IPlugin 的 provideTransformFlow 即可。

4、類圖對象

context.getClassGraph() 獲取類圖對象,兩個 TransformFlow 的類圖是隔離的。

5、MainProcessHandler

  • 通過複寫 process 方法,注册自己的 FlieProcessor 來處理。
  • FileProcessor 采用了責任鏈模式,每個 class 文件都會流經一系列的 FileProcessor 來處理。

6、IPlugin.hookTransformName()

「使用 反射 Hook 方式 將 Transform 注册到 proguard 之後」

三、ByteX 插件平臺構建流程探秘

添加 apply plugin: ‘bytex’ 之後,bytex 可以在 Gradle 的構建流程中起作用了。這裏的插件 id 為 bytex,我們找到 bytex.properties 文件,查看裏面映射的實現類,如下所示:

implementation-class=com.ss.android.ugc.bytex.base.ByteXPlugin

  • 1.

可以看到,bytex 的實現類為 ByteXPlugin,其源碼如下所示:

public class ByteXPlugin implements Plugin<Project> {
@Override
public void apply(@NotNull Project project) {
// 1
AppExtension android = project.getExtensions().getByType(AppExtension.class);
// 2
ByteXExtension extension = project.getExtensions().create("ByteX", ByteXExtension.class);
// 3
android.registerTransform(new ByteXTransform(new Context(project, android, extension)));
}
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

首先,注釋1處,獲取 Android 為 App 提供的擴展屬性 AppExtension 實例。然後,在注釋2處,獲取 ByteX 自身創建的擴展屬性 ByteXExtension 實例。最後,在注釋3處,注册 ByteXTransform 實例。ByteXTransform 繼承了抽象類 CommonTransform,其實現了關鍵的 transform 方法,其實現源碼如下所示:

@Override
public final void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {
super.transform(transformInvocation);
// 1、如果不是增量模式,則清楚輸出目錄的文件。
if (!transformInvocation.isIncremental()) {
transformInvocation.getOutputProvider().deleteAll();
}
// 2、獲取 transformContext 實例。
TransformContext transformContext = getTransformContext(transformInvocation);
// 3、初始化 HtmlReporter(生成 ByteX 構建產生日志的 HTML 文件)
init(transformContext);
// 4、過濾掉沒有打開插件開關的 plugin。
List<IPlugin> plugins = getPlugins().stream().filter(p -> p.enable(transformContext)).collect(Collectors.toList());
Timer timer = new Timer();
// 5、創建一個 transformEngine 實例。
TransformEngine transformEngine = new TransformEngine(transformContext);
try {
if (!plugins.isEmpty()) {
// 6、使用 PriorityQueue 對每一個 TransformFlow 進行優先級排序(在這裏添加的是與之對應的實現類 MainTransformFlow)。
Queue<TransformFlow> flowSet = new PriorityQueue<>((o1, o2) -> o2.getPriority() - o1.getPriority());
MainTransformFlow commonFlow = new MainTransformFlow(transformEngine);
flowSet.add(commonFlow);
for (int i = 0; i < plugins.size(); i++) {
// 7、給每一個 Plugin 注册 MainTransformFlow,其實質是將每一個 Plugin 的 MainProcessHandler 添加到 MainTransformFlow 中的 handlers 列錶中。
IPlugin plugin = plugins.get(i);
TransformFlow flow = plugin.registerTransformFlow(commonFlow, transformContext);
if (!flowSet.contains(flow)) {
flowSet.add(flow);
}
}
while (!flowSet.isEmpty()) {
TransformFlow flow = flowSet.poll();
if (flow != null) {
if (flowSet.size() == 0) {
flow.asTail();
}
// 8、按指定優先級執行每一個 TransformFlow 的 run 方法,默認只有一個 MainTransformFlow 實例。
flow.run();
// 9、獲取流中的 graph 類圖對象並清除。
Graph graph = flow.getClassGraph();
if (graph != null) {
//clear the class diagram.we won’t use it anymore
graph.clear();
}
}
}
} else {
transformEngine.skip();
}
// 10
afterTransform(transformInvocation);
} catch (Throwable throwable) {
LevelLog.sDefaultLogger.e(throwable.getClass().getName(), throwable);
throw throwable;
} finally {
for (IPlugin plugin : plugins) {
try {
plugin.afterExecute();
} catch (Throwable throwable) {
LevelLog.sDefaultLogger.e("do afterExecute", throwable);
}
}
transformContext.release();
release();
timer.record("Total cost time = [%s ms]");
if (BooleanProperty.ENABLE_HTML_LOG.value()) {
HtmlReporter.getInstance().createHtmlReporter(getName());
HtmlReporter.getInstance().reset();
}
}
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.

在注釋7處,調用了 plugin.registerTransformFlow 方法,其源碼如下所示:

@Nonnull
@Override
public final TransformFlow registerTransformFlow(@Nonnull MainTransformFlow mainFlow, @Nonnull TransformContext transformContext) {
if (transformFlow == null) {
transformFlow = provideTransformFlow(mainFlow, transformContext);
if (transformFlow == null) {
throw new RuntimeException("TransformFlow can not be null.");
}
}
return transformFlow;
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

這裏繼續調用了 provideTransformFlow 方法,其源碼如下所示:

/**
* create a new transformFlow or just return mainFlow and append a handler.
* It will be called by {@link IPlugin#registerTransformFlow(MainTransformFlow, TransformContext)} when
* handle start.
*
* @param mainFlow main TransformFlow
* @param transformContext handle context
* @return return a new TransformFlow object if you want make a new flow for current plugin
*/
protected TransformFlow provideTransformFlow(@Nonnull MainTransformFlow mainFlow, @Nonnull TransformContext transformContext) {
return mainFlow.appendHandler(this);
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

可以看到,通過調用 mainFlow.appendHandler(this) 方法將每一個 Plugin 的 MainProcessHandler 添加到 MainTransformFlow 中的 handlers 列錶之中。

在注釋8處,按指定優先級執行了每一個 TransformFlow 的 run 方法,默認只有一個 MainTransformFlow 實例。我們看到了 MianTransformFlow 的 run 方法:

@Override
public void run() throws IOException, InterruptedException {
try {
// 1
beginRun();
// 2
runTransform();
} finally {
// 3
endRun();
}
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

首先,在注釋1出,調用了 beginRun 方法,其實現如下:

// AbsTransformFlow
protected void beginRun() {
transformEngine.beginRun();
}
// TransformEngine
public void beginRun(){
context.markRunningState(false);
}
// TransformContext
private final AtomicBoolean running = new AtomicBoolean(false);
void markRunningState(boolean running) {
this.running.set(running);
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

最後,在 TransformContext 實例中使用了一個 AtomicBoolean 實例標記 MainTransformFlow 是否正在運行中。

然後,在注釋2處執行了 runTransform 方法,這裏就是真正執行 transform 的地方,其源碼如下所示:

private void runTransform() throws IOException, InterruptedException {
if (handlers.isEmpty()) return;
Timer timer = new Timer();
timer.startRecord("PRE_PROCESS");
timer.startRecord("INIT");
// 1、初始化 handlers 列錶中的每一個 handler。
for (MainProcessHandler handler : handlers) {
handler.init(transformEngine);
}
timer.stopRecord("INIT", "Process init cost time = [%s ms]");
// 如果不是 跳過 traverse 僅僅只執行 Transform 方法時,才執行 traverse 過程。
if (!isOnePassEnough()) {
if (!handlers.isEmpty() && context.isIncremental()) {
timer.startRecord("TRAVERSE_INCREMENTAL");
// 2、如果是 增量模式,則執行 traverseArtifactOnly(僅僅增量遍曆產物)調用每一個 plugin 的對應的 MainProcessHandler 的 traverseIncremental 方法。這裏最終會調用 ClassFileAnalyzer.handle 方法進行遍曆分發操作。
traverseArtifactOnly(getProcessors(Process.TRAVERSE_INCREMENTAL, new ClassFileAnalyzer(context, Process.TRAVERSE_INCREMENTAL, null, handlers)));
timer.stopRecord("TRAVERSE_INCREMENTAL", "Process project all .class files cost time = [%s ms]");
}
handlers.forEach(plugin -> plugin.beforeTraverse(transformEngine));
timer.startRecord("LOADCACHE");
// 3、創建一個 CachedGraphBuilder 對象:能够緩存 類圖 的 類圖構建者對象。
GraphBuilder graphBuilder = new CachedGraphBuilder(context.getGraphCache(), context.isIncremental(), context.shouldSaveCache());
if (context.isIncremental() && !graphBuilder.isCacheValid()) {
// 4、如果是增量更新 && graphBuilder 的緩存失效則直接請求非增量運行。
context.requestNotIncremental();
}
timer.stopRecord("LOADCACHE", "Process loading cache cost time = [%s ms]");
// 5、內部會調用 running.set(true) 來標記正在運行的狀態。
running();
if (!handlers.isEmpty()) {
timer.startRecord("PROJECT_CLASS");
// 6、執行 traverseArtifactOnly(遍曆產物)調用每一個 plugin 的對應的 MainProcessHandler 的 traverse 方法,這裏最終會調用 ClassFileAnalyzer.handle 方法進行遍曆分發操作。
traverseArtifactOnly(getProcessors(Process.TRAVERSE, new ClassFileAnalyzer(context, Process.TRAVERSE, graphBuilder, handlers)));
timer.stopRecord("PROJECT_CLASS", "Process project all .class files cost time = [%s ms]");
}
if (!handlers.isEmpty()) {
timer.startRecord("ANDROID");
// 7、僅僅遍曆 Android.jar
traverseAndroidJarOnly(getProcessors(Process.TRAVERSE_ANDROID, new ClassFileAnalyzer(context, Process.TRAVERSE_ANDROID, graphBuilder, handlers)));
timer.stopRecord("ANDROID", "Process android jar cost time = [%s ms]");
}
timer.startRecord("SAVECACHE");
// 8、構建 mClassGraph 類圖實例。
mClassGraph = graphBuilder.build();
timer.stopRecord("SAVECACHE", "Process saving cache cost time = [%s ms]");
}
timer.stopRecord("PRE_PROCESS", "Collect info cost time = [%s ms]");
if (!handlers.isEmpty()) {
timer.startRecord("PROCESS");
// 9、遍曆執行每一個 plugin 的 transform 方法。
transform(getProcessors(Process.TRANSFORM, new ClassFileTransformer(handlers, needPreVerify(), needVerify())));
timer.stopRecord("PROCESS", "Transform cost time = [%s ms]");
}
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.

首先,在注釋1處,遍曆調用了每一個 MainProcessHandler 的 init 方法,它是用於 transform 開始前的初始化實現方法。

MainProcessHandler 接口的 init 方法是一個 default 方法,裏面直接調用了每一個 pluign 實現的 init 方法(如果 plugin 沒有實現,則僅僅調用 CommonPlugin 的實現的 init 方法:這裏通常是用於把不需要處理的文件添加到 mWhiteList 列錶),這裏可以做一些plugin 的准備工作。

1、僅僅遍曆產物

traverseArtifactOnly(getProcessors(Process.TRAVERSE, new ClassFileAnalyzer(context, Process.TRAVERSE, graphBuilder, handlers)));

  • 1.

getProcessors 方法的源碼如下所示:

private FileProcessor[] getProcessors(Process process, FileHandler fileHandler) {
List<FileProcessor> processors = handlers.stream()
.flatMap((Function<MainProcessHandler, Stream<FileProcessor>>) handler -> handler.process(process).stream())
.collect(Collectors.toList());
switch (process) {
case TRAVERSE_INCREMENTAL:
processors.add(0, new FilterFileProcessor(fileData -> fileData.getStatus() != Status.NOTCHANGED));
processors.add(new IncrementalFileProcessor(handlers, ClassFileProcessor.newInstance(fileHandler)));
break;
case TRAVERSE:
case TRAVERSE_ANDROID:
case TRANSFORM:
processors.add(ClassFileProcessor.newInstance(fileHandler));
processors.add(0, new FilterFileProcessor(fileData -> fileData.getStatus() != Status.NOTCHANGED && fileData.getStatus() != Status.REMOVED))
break;
default:
throw new RuntimeException("Unknow Process:" + process);
}
## 最後
**分享一份工作1到5年以上的Android程序員架構進階學習路線體系,希望能對那些還在從事Android開發卻還不知道如何去提昇自己的,還處於迷茫的朋友!**
* 阿裏P7級Android架構師技術腦圖;查漏補缺,體系化深入學習提昇
* **[CodeChina開源項目地址:《Android學習筆記總結+移動架構視頻+大廠面試真題+項目實戰源碼》](https://ali1024.coding.net/public/P7/Android/git)**
![深入學習-Gradle-自動化構建技術(六,騰訊安卓面試_程序員](https://s7.51cto.com/images/20210918/1631915777191952.jpg)
* **全套體系化高級架構視頻;**七大主流技術模塊,視頻+源碼+筆記
![深入學習-Gradle-自動化構建技術(六,騰訊安卓面試_程序員_02](https://s2.51cto.com/images/20210918/1631915777984173.jpg)
有任何問題,歡迎廣大網友一起來交流

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
版权声明:本文为[mb612e2bd2b528b]所创,转载请带上原文链接,感谢。 https://gsmany.com/2021/09/20210918060638902m.html