Android Apt之Activity Route
前言
什麼是Apt
APT從原理上講是一個編譯期的註解處理工具(Annotation Processing Tool)。一些主流的三方庫(ButterKnife,Glide)都用到了這個技術來生成程式碼。-
Apt有什麼好處
- 自動生成模板程式碼,提高了開發效率
- 編譯期對註解的處理,相對於執行期對註解的處理,效能上要好的多。
Gradle指令碼中的apt和annotationProcessor
這兩個從廣義上說都是編譯期的註解處理工具。只不過android-apt
(其實是一個gradle外掛,apt
是外掛命令)是早期的github的一個開源專案,annotationProcessor
是gradle build tools 2.2之後自帶的編譯期註解工具(官方支援的,可替代開源的gradle外掛android-apt
)。android-apt
的作者已經發表宣告表示Android Studio外掛已經支援annotationProcessor
,並且會警告和阻止使用android-apt
。總的來說,看你的gradle build tools的版本,低版本用android-apt
(需要引入外掛),高版本用annotationProcessor
(無需引入外掛)
程式碼設計
- 需求分析
這裡將route模組分成三部分(一個android library,兩個java library)
- router-annotation(java library)
這裡java工程裡面只放註解的宣告類。這裡只實現了兩個註解RouterActivity
、RouterField
。 - router-compiler (java library)
這個工程是編譯期依賴的工程,作用是編譯期掃描程式碼,根據RouterActivity
、RouterField
這兩個註解的使用,生成相關程式碼。這裡需要講下如何掃描程式碼並且生成程式碼的。這部分功能的實現主要依賴兩個庫:Google的auto-service
(掃描程式碼),Squareup的javapoet
(生成程式碼) - router (android library)
主要邏輯程式碼。在這個模組中會定義一些功能類和介面。router-compiler
模組可以根據這些介面和功能類generate邏輯程式碼。需要注意的是router-compiler
是不需要依賴router
的,router-compiler
是根據包名+類名的方式獲取類的。
程式碼實現
router-annotation
RouterActivity
是一個註解,用此註解修飾的Activity根據指定的路由地址,會自動新增到路由表中,當系統掛載了路由表之後,就可根據指定的路由地址來訪問特定的Activity了。程式碼如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface RouterActivity {
String[] value();
}
這裡Activity可用多個路由地址修改。
RouterField
是一個用於表示Activity跳轉時引數傳遞的註解,用這個註解修飾的成員變數,表示為接收Intent引數的變數。
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RouterField {
String[] value();
}
router-compiler
這個模組只包含一個類RouterProcessor
,這個類的大致結構如下:
//此處用AutoService註解,就可實現編譯期自動掃描程式碼
@AutoService(Processor.class)
public class RouterProcessor extends AbstractProcessor{
private Elements elementUtils;
private String targetModuleName = "";
@Override
public Set<String> getSupportedAnnotationTypes() {
//支援的註解型別
return Collections.singleton(RouterActivity.class.getCanonicalName());
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
//處理程式碼掃描結果的關鍵函式
...
return true;
}
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
//在掃描程式碼之前可從build.gradle中讀取一些配置項
}
@Override
public SourceVersion getSupportedSourceVersion() {
//表示支援的Jdk版本
return SourceVersion.RELEASE_7;
}
}
下面分別講解一下函式的實現:
-
init
函式
我們的專案大多都是多module的形式,這時候我們就需要為每個module建立一個Activity路由登錄檔,然後在Application初始化的時候將所有的路由登錄檔掛載上,達到Activity路由跳轉的目的。這裡我們在init
函式中,配置每個模組路由表的字首名稱。
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
elementUtils = processingEnvironment.getElementUtils();
Map<String, String> map = processingEnvironment.getOptions();
Set<String> keys = map.keySet();
for (String key: keys) {
if ("targetModuleName".equals(key)) {
this.targetModuleName = map.get(key);
}
System.out.println(key + " + " + map.get(key));
並在module的build.gradle檔案下配置如下程式碼:
apt {
arguments {
targetModuleName 'moduleName'
}
}
-
process
函式
這個函式的大致流程如下:找到所有被RouterActivity修飾的Activity;實現router
模組中的RouterInitializer
介面,將每個Activity的路由地址加入路由表中;同時為每個Activity建立一個XXXActivityHelper(用於更友好的Activity調整),並將每個XXXAcitivyHelper放入RouterHelper中,提供get方法獲取。process
函式的具體實現,可詳見專案原始碼(都是一些程式碼生成的語句,沒有多少邏輯)。
router
-
RouterInitializer
介面,用於每個module登錄檔的實現 -
ActivityHelper
,封裝了一些引數解析邏輯,更方便的Activity跳轉 -
SafeBundle
, 對Activity的引數進行了封裝 -
Router
, 路由核心類,支援url跳轉,解析url,並實現跳轉。 - 'RouterCenterActivity', 可被外部瀏覽器喚起的中轉Activity(外面根據url scheme喚醒
RouterCenterActivity
,RouterCenterActivity
分發路由地址)
程式碼使用
- 初始化Router
public class DemoApp extends Application {
@Override
public void onCreate() {
super.onCreate();
Router.init("demo"); //自定義scheme協議
}
}
- Activity跳轉
@RouterActivity({"main"})
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btn_second).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
RouterHelper.getSecondActivityHelper().start(MainActivity.this);
}
});
}
}
@RouterActivity({"second"})
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
}
}
build目錄生成的程式碼如下:
詳細程式碼可檢視:Github專案。
現階段程式碼還不完善,後期會新增更多功能。
相關文章
- Android之ActivityAndroid
- Android之Activity全面解析Android
- android 開發之 APT 技術AndroidAPT
- Android 註解系列之APT工具(三)AndroidAPT
- Android基礎之Activity全解析Android
- Android之Activity基類封裝Android封裝
- Android開發之浮動ActivityAndroid
- Android 四大元件之 ActivityAndroid元件
- Android全面解析之Activity生命週期Android
- Android四大元件之ActivityAndroid元件
- Android開發之Activity轉場動畫Android動畫
- Android 四大元件之 " Activity "Android元件
- android之兩個activity相互跳轉Android
- Android ActivityAndroid
- Android四大元件之Activity篇Android元件
- Android 之 Activity 生命週期淺析(一)Android
- 初識Android之Activity的生命週期Android
- 深入理解Android 之 Activity啟動流程(Android 10)Android
- Android知識點回顧之Activity基礎Android
- 【Android】安卓四大元件之Activity(二)Android安卓元件
- Android面試常客--四大元件之ActivityAndroid面試元件
- Android 之 Activity 生命週期的淺析(二)Android
- Android應用鎖之獲取棧頂ActivityAndroid
- Android 中MVC例項之Activity,Window和ViewAndroidMVCView
- Android學習之 Activity堆疊管理與控制Android
- Android基礎之Activity 執行模式與回退棧Android模式
- Android 中Activity,Window和View之間的關係AndroidView
- Android在多個Activity之間共享一個ViewAndroidView
- Android Activity 重建之狀態儲存與恢復Android
- Android之android:theme設定在Application 和 Activity的區別AndroidAPP
- Android四大元件之Activity----重新認識Android(4)Android元件
- [Android]關閉所有Activity,開啟某個ActivityAndroid
- 完全看懂 Android 四大元件之 Activity(上)Android元件
- apt 和 apt-get 之間有什麼區別?apt-get
- 仿寫Android的ActivityAndroid
- Android Activity生命週期Android
- Android Activity的基本理解Android
- Android退出多個ActivityAndroid