Android Apt之Activity Route的示例
前言
什么是Apt
APT從原理上講是一個(gè)編譯期的注解處理工具(Annotation Processing Tool)。一些主流的三方庫(ButterKnife,Glide)都用到了這個(gè)技術(shù)來生成代碼。
Apt有什么好處
- 自動生成模板代碼,提高了開發(fā)效率
- 編譯期對注解的處理,相對于運(yùn)行期對注解的處理,性能上要好的多。
Gradle腳本中的apt和annotationProcessor
這兩個(gè)從廣義上說都是編譯期的注解處理工具。只不過android-apt(其實(shí)是一個(gè)gradle插件,apt是插件命令)是早期的github的一個(gè)開源項(xiàng)目,annotationProcessor是gradle build tools 2.2之后自帶的編譯期注解工具(官方支持的,可替代開源的gradle插件android-apt)。android-apt的作者已經(jīng)發(fā)表聲明表示Android Studio插件已經(jīng)支持annotationProcessor,并且會警告和阻止使用android-apt。總的來說,看你的gradle build tools的版本,低版本用android-apt(需要引入插件),高版本用annotationProcessor(無需引入插件)
代碼設(shè)計(jì)
需求分析
這里將route模塊分成三部分(一個(gè)android library,兩個(gè)java library)
1、router-annotation(java library)
這里java工程里面只放注解的聲明類。這里只實(shí)現(xiàn)了兩個(gè)注解RouterActivity、RouterField。
2、router-compiler (java library)
這個(gè)工程是編譯期依賴的工程,作用是編譯期掃描代碼,根據(jù)RouterActivity、RouterField這兩個(gè)注解的使用,生成相關(guān)代碼。這里需要講下如何掃描代碼并且生成代碼的。這部分功能的實(shí)現(xiàn)主要依賴兩個(gè)庫:Google的auto-service(掃描代碼),Squareup的javapoet(生成代碼)
3、router (android library)
主要邏輯代碼。在這個(gè)模塊中會定義一些功能類和接口。router-compiler模塊可以根據(jù)這些接口和功能類generate邏輯代碼。需要注意的是router-compiler是不需要依賴router的,router-compiler是根據(jù)包名+類名的方式獲取類的。
代碼實(shí)現(xiàn)
router-annotation
RouterActivity是一個(gè)注解,用此注解修飾的Activity根據(jù)指定的路由地址,會自動添加到路由表中,當(dāng)系統(tǒng)掛載了路由表之后,就可根據(jù)指定的路由地址來訪問特定的Activity了。代碼如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface RouterActivity {
String[] value();
}
這里Activity可用多個(gè)路由地址修改。
RouterField是一個(gè)用于表示Activity跳轉(zhuǎn)時(shí)參數(shù)傳遞的注解,用這個(gè)注解修飾的成員變量,表示為接收Intent參數(shù)的變量。
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RouterField {
String[] value();
}
router-compiler
這個(gè)模塊只包含一個(gè)類RouterProcessor,這個(gè)類的大致結(jié)構(gòu)如下:
//此處用AutoService注解,就可實(shí)現(xiàn)編譯期自動掃描代碼
@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) {
//處理代碼掃描結(jié)果的關(guān)鍵函數(shù)
...
return true;
}
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
//在掃描代碼之前可從build.gradle中讀取一些配置項(xiàng)
}
@Override
public SourceVersion getSupportedSourceVersion() {
//表示支持的Jdk版本
return SourceVersion.RELEASE_7;
}
}
下面分別講解一下函數(shù)的實(shí)現(xiàn):
1、init函數(shù)
我們的項(xiàng)目大多都是多module的形式,這時(shí)候我們就需要為每個(gè)module創(chuàng)建一個(gè)Activity路由注冊表,然后在Application初始化的時(shí)候?qū)⑺械穆酚勺员頀燧d上,達(dá)到Activity路由跳轉(zhuǎn)的目的。這里我們在init函數(shù)中,配置每個(gè)模塊路由表的前綴名稱。
@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'
}
}
2、process函數(shù)
這個(gè)函數(shù)的大致流程如下:找到所有被RouterActivity修飾的Activity;實(shí)現(xiàn)router模塊中的RouterInitializer接口,將每個(gè)Activity的路由地址加入路由表中;同時(shí)為每個(gè)Activity創(chuàng)建一個(gè)XXXActivityHelper(用于更友好的Activity調(diào)整),并將每個(gè)XXXAcitivyHelper放入RouterHelper中,提供get方法獲取。process函數(shù)的具體實(shí)現(xiàn),可詳見項(xiàng)目源碼(都是一些代碼生成的語句,沒有多少邏輯)。
router
- RouterInitializer接口,用于每個(gè)module注冊表的實(shí)現(xiàn)
- ActivityHelper,封裝了一些參數(shù)解析邏輯,更方便的Activity跳轉(zhuǎn)
- SafeBundle, 對Activity的參數(shù)進(jìn)行了封裝
- Router, 路由核心類,支持url跳轉(zhuǎn),解析url,并實(shí)現(xiàn)跳轉(zhuǎn)。
- 'RouterCenterActivity', 可被外部瀏覽器喚起的中轉(zhuǎn)Activity(外面根據(jù)url scheme喚醒RouterCenterActivity,RouterCenterActivity分發(fā)路由地址)
代碼使用
初始化Router
public class DemoApp extends Application {
@Override
public void onCreate() {
super.onCreate();
Router.init("demo"); //自定義scheme協(xié)議
}
}
Activity跳轉(zhuǎn)
@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目錄生成的代碼如下:

詳細(xì)代碼可查看:Github項(xiàng)目。
現(xiàn)階段代碼還不完善,后期會添加更多功能。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android自定義Adapter的ListView的思路及代碼
- Android快速分析apk工具aapt的使用教程
- android錯(cuò)誤 aapt.exe已停止工作的解決方法
- android開發(fā)中ListView與Adapter使用要點(diǎn)介紹
- 舉例講解Android應(yīng)用中SimpleAdapter簡單適配器的使用
- 詳解Android App中ViewPager使用PagerAdapter的方法
- Android中 自定義數(shù)據(jù)綁定適配器BaseAdapter的方法
- Android自定義Spinner下拉列表(使用ArrayAdapter和自定義Adapter實(shí)現(xiàn))
- Android aapt自動打包工具詳細(xì)介紹
相關(guān)文章
詳解Android Studio3.5及使用AndroidX的一些坑
這篇文章主要介紹了詳解Android Studio3.5及使用AndroidX的一些坑,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11
Android開發(fā)中多進(jìn)程共享數(shù)據(jù)簡析
這篇文章主要為大家簡單分析Android開發(fā)中多進(jìn)程共享數(shù)據(jù),怎么做才能讓這兩邊共享數(shù)據(jù),感興趣的小伙伴們可以參考一下2016-04-04
Android App中ListView仿QQ實(shí)現(xiàn)滑動刪除效果的要點(diǎn)解析
這篇文章主要介紹了Android App中ListView仿QQ實(shí)現(xiàn)滑動刪除效果的要點(diǎn)解析,重點(diǎn)是要判斷手勢按下的位置坐標(biāo),需要的朋友可以參考下2016-04-04
Android ContentProvider查看/讀取手機(jī)聯(lián)系人實(shí)例
本篇文章主要介紹了Android ContentProvider查看/讀取手機(jī)聯(lián)系人實(shí)例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-02-02
Android編程實(shí)現(xiàn)3D旋轉(zhuǎn)效果實(shí)例
這篇文章主要介紹了Android編程實(shí)現(xiàn)3D旋轉(zhuǎn)效果的方法,基于Android的Camera類實(shí)現(xiàn)坐標(biāo)變換達(dá)到圖片3D旋轉(zhuǎn)效果,需要的朋友可以參考下2016-01-01
android開發(fā)教程之時(shí)間對話框核心代碼
這篇文章主要介紹了android的時(shí)間對話框核心代碼,需要的朋友可以參考下2014-04-04

