前言 在組件化開(kāi)發(fā)中一個(gè)必須要面對(duì)的問(wèn)題就是組件間頁(yè)面跳轉(zhuǎn),實(shí)現(xiàn)的方法有很多,簡(jiǎn)單的可以通過(guò)反射獲取,但是比較耗費(fèi)性能,也可以通過(guò)隱式跳轉(zhuǎn),但是隨著頁(yè)面的增多,過(guò)濾條件會(huì)隨之增多,后期維護(hù)麻煩。那還有什么方法呢,沒(méi)錯(cuò),就是接下來(lái)要介紹的Arouter路由框架,該框架是阿里巴巴開(kāi)源項(xiàng)目,大廠出品,必屬精品。使用過(guò)Arouter得同學(xué)都知道Arouter是通過(guò)給每個(gè)頁(yè)面添加@Route注解然后調(diào)用一定的方法實(shí)現(xiàn)跳轉(zhuǎn)的,而Arouter的核心就是這個(gè)注解。 ??這里要介紹一個(gè)概念,APT(Annotation Processing Tool)即注解處理器,是一種處理注解的工具,它用來(lái)在編譯時(shí)掃描和處理注解,注解處理器以Java代碼(或者編譯過(guò)的字節(jié)碼)作為輸入,生成.java文件作為輸出。簡(jiǎn)單來(lái)說(shuō)就是在編譯期,通過(guò)注解生成.java文件。 ??Arouter的路由表就是在該工具下在編譯期生成的,說(shuō)簡(jiǎn)單了,就是利用注解在編譯期生成了一些java文件,我們?cè)谶@些新的java文件中將所有被注解的頁(yè)面添加進(jìn)了路由表中。
設(shè)計(jì)思路arouter-compiler:注解編譯處理器,引入“arouter-annotation”,在編譯器把注解標(biāo)注的相關(guān)目標(biāo)類(lèi)生成映射文件,包含路由框架所使用的全部注解,及其相關(guān)類(lèi) arouter-api:實(shí)現(xiàn)路由控制
實(shí)現(xiàn)效果
步驟- 新建module java library(router_compiler)(因?yàn)樵谥?Module 中無(wú)法找到 AbstractProcessor 類(lèi))
- 新建module android library(router_api),步驟如上,但是要注意選擇Android library。
- 在route-compiler的gradle文件中導(dǎo)入依賴(lài)和jdk版本支持
apply plugin: 'java-library'dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) api 'com.squareup:javapoet:1.11.1' api 'org.apache.commons:commons-collections4:4.4' api 'org.apache.commons:commons-lang3:3.5'}sourceCompatibility = "8"targetCompatibility = "8" 在app工程gradle文件中添加jdk版本支持compileOptions { sourceCompatibility 1.8 targetCompatibility 1.8}
- 在route_api和app模塊等其他組件化模塊的gradle文件中導(dǎo)入route_compiler模塊
annotationProcessor project(':router_compiler')api project(':router_compiler')
- 在每個(gè)module模塊中的gradle文件中添加下列語(yǔ)句用來(lái)獲取每個(gè)module的包名
javaCompileOptions { annotationProcessorOptions { arguments = [ROUTER_MODULE_NAME: project.getName()] }}
- 在router_compiler模塊中創(chuàng)建RouteProcessor類(lèi)并繼承自AbstractProcessor
- 在router_compiler模塊中的main文件夾下創(chuàng)建文件夾resources/META-INF/services,然后創(chuàng)建javax.annotation.processing.Processor文件,并添加下列語(yǔ)句
com.nsyw.routerdemo.router_compiler.RouteProcessor
- 在router-compiler根目錄下新建注解類(lèi)Route
public @interface Route { /** * Path of route */ String path();}
- 創(chuàng)建接口IRoute,自動(dòng)生成的java文件都要繼承自該接口
public interface IRoute { /** * * @param routes 模塊下的路由集合 */ void loadInto(Map routes);}
/** * @SupportedAnnotationTypes表示支持的注解類(lèi)型 */@SupportedAnnotationTypes("com.nsyw.routerdemo.router_compiler.annotation.Route")public class RouteProcessor extends AbstractProcessor { ...... @Override public synchronized void init(ProcessingEnvironment processingEnvironment) { ...... } @Override public boolean process(Set extends TypeElement> set, RoundEnvironment roundEnvironment) { ParameterizedTypeName inputMapTypeOfGroup = ParameterizedTypeName.get( ClassName.get(Map.class), ClassName.get(String.class), ClassName.get(RouteMeta.class) ); ParameterSpec groupParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "routes").build(); /* methodBuilder 方法名 addAnnotation 方法添加注解 addModifiers 方法訪問(wèn)限制類(lèi)型 addParameter 添加參數(shù) */ MethodSpec.Builder loadIntoMethodOfGroupBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO) .addAnnotation(Override.class) .addModifiers(PUBLIC) .addParameter(groupParamSpec); ClassName routeMetaCn = ClassName.get(RouteMeta.class); ClassName routeTypeCn = ClassName.get(RouteType.class); //遍歷@Route注解的所有Activity for (Element element : routeElements) { TypeMirror tm = element.asType(); //獲取注解 Route route = element.getAnnotation(Route.class); RouteMeta routeMeta = null; if (types.isSubtype(tm, type_Activity)) { routeMeta = new RouteMeta(route.path(), RouteType.ACTIVITY); } //獲取被注解的類(lèi)的類(lèi)名 ClassName className = ClassName.get((TypeElement) element); /* 方法內(nèi)的添加路由語(yǔ)句 routes.put(routeMeta.getPath(),RouteMeta.build(routeMeta.getPath(),RouteType.ACTIVITY,className.class)) */ loadIntoMethodOfGroupBuilder.addStatement( "routes.put($S,$T.build($S,$T." + routeMeta.getRouteType() + ", $T.class))", routeMeta.getPath(), routeMetaCn, routeMeta.getPath(), routeTypeCn, className); } /* 構(gòu)建java文件 */ try { JavaFile.builder(PACKAGE_OF_GENERATE_FILE, TypeSpec.classBuilder(NAME_OF_ROUTE + moduleName) .addJavadoc(WARNING_TIPS) .addSuperinterface(ClassName.get(mElementsUtil.getTypeElement(IROUTE_LOAD))) .addModifiers(PUBLIC) .addMethod(loadIntoMethodOfGroupBuilder.build()) .build() ).build().writeTo(mFiler); } catch (IOException e) { e.printStackTrace(); } return true; } return false; }}
- 在router_api模塊下創(chuàng)建Router
public class Router { private static volatile Router mInstance = new Router(); private Context mContext; private String path; private Map map = new HashMap<>(); public static void init(Application application) { mInstance.mContext = application; Set routerMap; try { routerMap = ClassUtils.getFileNameByPackageName(mInstance.mContext, consts.PACKAGE_OF_GENERATE_FILE); Log.e("Router", routerMap.toString()); for (String className : routerMap) { ((IRoute) (Class.forName(className).getConstructor().newInstance())).loadInto(mInstance.map); } } catch (PackageManager.NameNotFoundException | InterruptedException | IOException | ClassNotFoundException | NoSuchMethodException | InstantiationException | InvocationTargetException | IllegalAccessException e) { e.printStackTrace(); } } public static synchronized Router getInstance() { return mInstance; } public Router build(String path) { mInstance.path = path; return mInstance; } public void navigation(Context context) { RouteMeta routeMeta = mInstance.map.get(mInstance.path); if (routeMeta != null) { context.startActivity(new Intent(context, routeMeta.getClazz())); } }}
public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); Router.init(this); }}
在AndroidManifest文件的application節(jié)點(diǎn)添加下列語(yǔ)句 android:name=".MyApplication"
- 項(xiàng)目build的完之后會(huì)在各個(gè)模塊的相應(yīng)的文件夾下生成java文件,這些文件會(huì)被Router依次獲取將路由信息存入路由表中。
以下代碼是編譯器自動(dòng)生成的 package com.nsyw.routerdemo.routes;import com.nsyw.routerdemo.MainOneActivity;import com.nsyw.routerdemo.MainTwoActivity;import com.nsyw.routerdemo.router_compiler.IRoute;import com.nsyw.routerdemo.router_compiler.RouteMeta;import com.nsyw.routerdemo.router_compiler.RouteType;import java.lang.Override;import java.lang.String;import java.util.Map;/** * DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */public class Router$$App$$app implements IRoute { @Override public void loadInto(Map routes) { routes.put("/main/one",RouteMeta.build("/main/one",RouteType.ACTIVITY, MainOneActivity.class)); routes.put("/main/two",RouteMeta.build("/main/two",RouteType.ACTIVITY, MainTwoActivity.class)); }}
Router.getInstance().build("/main/one").navigation(MainActivity.this);
小結(jié)Router只是參照ARouter手動(dòng)實(shí)現(xiàn)的路由框架,剔除掉了很多東西,只實(shí)現(xiàn)了組件間Activity之間的跳轉(zhuǎn),如果想要用在項(xiàng)目里,建議還是用ARouter更好,畢竟這只是個(gè)練手項(xiàng)目,功能也不夠全面,當(dāng)然有同學(xué)想對(duì)demo擴(kuò)展后使用那當(dāng)然更好,遇到什么問(wèn)題可以及時(shí)聯(lián)系我。我的目的是通過(guò)自己手動(dòng)實(shí)現(xiàn)路由框架來(lái)加深對(duì)知識(shí)的理解,如這里面涉及到的知識(shí)點(diǎn)apt、javapoet和組件化思路、編寫(xiě)框架的思路等??吹竭@里,如果感覺(jué)干貨很多,歡迎關(guān)注我的github,里面會(huì)有更多干貨! |