西峰住房和城鄉(xiāng)建設(shè)局網(wǎng)站怎么建網(wǎng)站平臺(tái)賣東西
一、簡(jiǎn)介
眾所周知,在日常開發(fā)中,隨著項(xiàng)目業(yè)務(wù)越來(lái)越復(fù)雜,項(xiàng)目中的代碼量也越來(lái)越多,如果維護(hù)、擴(kuò)展、解耦等成了一個(gè)非常頭疼問(wèn)題,隨之孕育而生的諸如插件化、組件化、模塊化等熱門技術(shù)。 而其中組件化中一項(xiàng)的難點(diǎn),就是實(shí)現(xiàn)各個(gè)組件之間的通訊,我們通常解決方案采用路由中間件,來(lái)實(shí)現(xiàn)頁(yè)面之間跳轉(zhuǎn)關(guān)系。 ARouter 是阿里開源路由框架,常被用于組件之間、模塊之間的跳轉(zhuǎn),由于是國(guó)人團(tuán)隊(duì)開發(fā)的,所以你懂的,中文文檔非常詳細(xì)。
二、入門
2.1.添加依賴
android {defaultConfig {...javaCompileOptions {annotationProcessorOptions {arguments = [AROUTER_MODULE_NAME: project.getName()]}}}
}dependencies {api'com.alibaba:arouter-api:1.5.0'annotationProcessor 'com.alibaba:arouter-compiler:1.2.2'
}
2.2.初始化
在 Application 中初始化
if (BuildConfig.DEBUG) {ARouter.openLog() // 打印日志ARouter.openDebug() // 開啟調(diào)試模式(如果在InstantRun模式下運(yùn)行,必須開啟調(diào)試模式!線上版本需要關(guān)閉,否則有安全風(fēng)險(xiǎn))
}
ARouter.init(this);
2.3.添加注解
@Route(path = "/main/main_main")
public class MainActivity extend BaseActivity {...
}
2.4.發(fā)起路由
// 1.應(yīng)用內(nèi)簡(jiǎn)單的跳轉(zhuǎn)(通過(guò)URL跳轉(zhuǎn)在'進(jìn)階用法'中)
ARouter.getInstance().build("/main/main_main").navigation();// 2.跳轉(zhuǎn)并攜帶參數(shù)
ARouter.getInstance().build("/main/main_main").withLong("id", 10086L).withString("name", "Test").navigation();
三、原理解析
在原理解析之前,我們先了解 ARouter 使用關(guān)鍵技術(shù)-APT(Annotation Processing Tool),它是 javac 的一個(gè)工具,中文譯名為編譯時(shí)注解處理器,說(shuō)白了,APT 用來(lái)編譯時(shí),掃描和處理注解,獲取注解和被注解類等相關(guān)信息,拿到這些信息之后,自動(dòng)生成一些代碼,核心是 AbstractProcessor 這個(gè)類,APT 運(yùn)用非常廣泛,諸如 ButterKnife、EventBus、Dagger2 等使用運(yùn)用到了 APT,ARouter 也不例外。運(yùn)用 APT 技術(shù)我們可以自己寫一些注解處理器,例如處理網(wǎng)絡(luò)、打印出錯(cuò)信息等。
3.1 分析
我們來(lái)看看 ARouter 初始化
//1.初始化
ARouter.init(application)//2.ARouter#init
public static void init(Application application) {if (!hasInit) {logger = _ARouter.logger;_ARouter.logger.info(Consts.TAG, "ARouter init start.");//委托給_ARouter去初始化hasInit = _ARouter.init(application);if (hasInit) {_ARouter.afterInit();}//初始化之后調(diào)用afterInit_ARouter.logger.info(Consts.TAG, "ARouter init over.");}}
從上面我們可以看到 ARouter 采用門面模式,實(shí)際上委托給 *ARouter 處理,*ARouter 是整個(gè)框架的路由中心控制器,負(fù)責(zé)處理控制整個(gè)路由的流程。接下來(lái),我們看看 _ARouter 初始化化。
protected static synchronized boolean init(Application application) {mContext = application;//調(diào)用 LogisticsCenter 的初始化LogisticsCenter.init(mContext, executor);logger.info(Consts.TAG, "ARouter init success!");hasInit = true;mHandler = new Handler(Looper.getMainLooper());return true;
}//LogisticsCenter#init
public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {mContext = context;executor = tpe;try {long startInit = System.currentTimeMillis();loadRouterMap();if (registerByPlugin) {logger.info(TAG, "Load router map by arouter-auto-register plugin.");} else {Set<String> routerMap;//1.如果是debug模式,或者有更新if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {logger.info(TAG, "Run with debug mode or new install, rebuild router map.");//1.掃描包,獲取ROUTE_ROOT_PAKCAGE(com.alibaba.android.arouter.routes)包下的類routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);if (!routerMap.isEmpty()) {context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).edit().putStringSet(AROUTER_SP_KEY_MAP, routerMap).apply();}PackageUtils.updateVersion(context); // Save new version name when router map update finishes.} else {logger.info(TAG, "Load router map from cache.");//2.獲取本地緩存routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet<String>()));}logger.info(TAG, "Find router map finished, map size = " + routerMap.size() + ", cost " + (System.currentTimeMillis() - startInit) + " ms.");startInit = System.currentTimeMillis();for (String className : routerMap) {//3.將 IRouteRoot,IRouteGroup和IProviderGroup的實(shí)現(xiàn)類,//通過(guò)注解生成,并且加載 Warehouse(數(shù)據(jù)倉(cāng)庫(kù))// Warehouse:數(shù)據(jù)倉(cāng)庫(kù),存儲(chǔ)路由配置信息和具體生成的IProvider對(duì)象if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {//1.加載 IRouteRoot,每個(gè)moudle下都會(huì)生成一個(gè)該類型的實(shí)現(xiàn)類,//通過(guò)module名來(lái)區(qū)分的,作用是將每個(gè)module下所有的分組按照組名//和對(duì)應(yīng)分組的實(shí)現(xiàn)類(IRouteGroup接口的實(shí)現(xiàn)類)的 Class 對(duì)象做一個(gè)映射,//然后保存在一個(gè)全局的 groupIndex 的 map 表中。((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {//2.加載 IInterceptorGroup 作用是將各個(gè)module下的 自定義的i nterceptor 按照優(yōu)先級(jí)和 interceptor的 // Class 對(duì)象做一個(gè)映射,然后保存在一個(gè)全局的 interceptorIndex 的 map 表中。((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {//3.加載 IProviderGroup 該類的作用的是將項(xiàng)目中自定義的提供序//列化功能的類的相關(guān)信息以RouteMeta 類的對(duì)象保存在全局的providerIndex的map表中((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);}}}logger.info(TAG, "Load root element finished, cost " + (System.currentTimeMillis() - startInit) + " ms.");if (Warehouse.groupsIndex.size() == 0) {logger.error(TAG, "No mapping files were found, check your configuration please!");}if (ARouter.debuggable()) {logger.debug(TAG, String.format(Locale.getDefault(), "LogisticsCenter has already been loaded, GroupIndex[%d], InterceptorIndex[%d], ProviderIndex[%d]", Warehouse.groupsIndex.size(), Warehouse.interceptorsIndex.size(), Warehouse.providersIndex.size()));}} catch (Exception e) {throw new HandlerException(TAG + "ARouter init logistics center exception! [" + e.getMessage() + "]");}}
從上面代碼我們可以看到調(diào)用 LogisticsCenter,后勤中心主要完成兩件事
-
獲取到 com.alibaba.android.arouter.routes 包下的所有 class 文件類名
-
根據(jù)找到的類名去加載相關(guān)的實(shí)例到Warehouse中,com.alibaba.android.arouter.routes 包下面的 class 是注解解析器自動(dòng)生成,主要 IRouteRoot,IRouteGroup 和 IProviderGroup 的實(shí)現(xiàn)類,當(dāng)我們使用 @Route 注解某個(gè)類時(shí),會(huì)將這個(gè)類的信息注入的到自動(dòng)生成的上述實(shí)現(xiàn)類中。 接下來(lái)調(diào)用 afterInit()。
//_ARouter#afterInit
static void afterInit() {// 調(diào)用 Postcard#build 方法,獲取 InterceptorService 攔截服務(wù)控制器interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();}//build 方法實(shí)際上,將 path 和 group 信息封裝到 Postcard,生成一個(gè)要跳轉(zhuǎn)的信息表protected Postcard build(String path) {if (TextUtils.isEmpty(path)) {throw new HandlerException(Consts.TAG + "Parameter is invalid!");} else {//生成具體實(shí)例PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);if (null != pService) {path = pService.forString(path);}return build(path, extractGroup(path));}}//Postcard#navigation 這個(gè)方法實(shí)現(xiàn)了跳轉(zhuǎn),我們點(diǎn)進(jìn)去會(huì)發(fā)現(xiàn),最后調(diào)用 _ARouter#navigation
//_ARouter#navigation
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {PretreatmentService pretreatmentService = ARouter.getInstance().navigation(PretreatmentService.class);if (null != pretreatmentService && !pretreatmentService.onPretreatment(context, postcard)) {// Pretreatment failed, navigation canceled.return null;}try {//1.調(diào)用 LogisticsCenter#completion 的方法LogisticsCenter.completion(postcard);......//不是綠色通道,通過(guò)攔截控制器依次調(diào)用不同攔截器處理信息 if (!postcard.isGreenChannel()) { //每個(gè)攔截器的攔截方法調(diào)用都是在子線程中執(zhí)行的interceptorService.doInterceptions(postcard, new InterceptorCallback() {@Overridepublic void onContinue(Postcard postcard) {_navigation(context, postcard, requestCode, callback);}@Overridepublic void onInterrupt(Throwable exception) {if (null != callback) {//只要有一個(gè)攔截器攔截該包裹,則回調(diào)onInterrupt方法宣告本次路由被終止callback.onInterrupt(postcard);}}});} else {//2.如果是綠色通道,調(diào)用_navigation方法進(jìn)行具體的導(dǎo)航return _navigation(context, postcard, requestCode, callback);}return null;} }//LogisticsCenter#completion
public synchronized static void completion(Postcard postcard) {......//1.Warehouse.routes獲取RouteMeta,RouteMeta 路由信息描述類,存儲(chǔ)目標(biāo)地址的類型,路徑,參數(shù)等信RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());if (null == routeMeta) { //如果沒(méi)有路由信息,則嘗試去數(shù)據(jù)倉(cāng)庫(kù)查找Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup()); if (null == groupMeta) {throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");} else {// Load route and cache it into memory, then delete from metas.try {if (ARouter.debuggable()) {logger.debug(TAG, String.format(Locale.getDefault(), "The group [%s] starts loading, trigger by [%s]", postcard.getGroup(), postcard.getPath()));}IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();iGroupInstance.loadInto(Warehouse.routes);Warehouse.groupsIndex.remove(postcard.getGroup());if (ARouter.debuggable()) {logger.debug(TAG, String.format(Locale.getDefault(), "The group [%s] has already been loaded, trigger by [%s]", postcard.getGroup(), postcard.getPath()));}} catch (Exception e) {throw new HandlerException(TAG + "Fatal exception when loading group meta. [" + e.getMessage() + "]");}completion(postcard); // Reload} else {//找到路由信息后,則將配置的路由信息填充到Postcard對(duì)象中postcard.setDestination(routeMeta.getDestination());//要跳轉(zhuǎn) Activity.class 路徑postcard.setType(routeMeta.getType());postcard.setPriority(routeMeta.getPriority());postcard.setExtra(routeMeta.getExtra());Uri rawUri = postcard.getUri();if (null != rawUri) { //這里主要是完成參數(shù)的填充}//針對(duì)不同的路由類型進(jìn)行處理switch (routeMeta.getType()) {case PROVIDER: //如果是服務(wù)提供者,則嘗試獲取其具體實(shí)例,如果沒(méi)有,則根據(jù)路由信息構(gòu)造一個(gè)實(shí)例,初始化并存儲(chǔ)到數(shù)據(jù)倉(cāng)庫(kù),Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();IProvider instance = Warehouse.providers.get(providerMeta);if (null == instance) { // There's no instance of this providerIProvider provider;provider = providerMeta.getConstructor().newInstance();provider.init(mContext);Warehouse.providers.put(providerMeta, provider);instance = provider;}postcard.setProvider(instance);//服務(wù)提供者被設(shè)置成綠色渠道,不用接受攔截檢查postcard.greenChannel(); break;case FRAGMENT://fragment也不用攔截檢查postcard.greenChannel(); default:break;}}//_ARouter#_navigation
//根據(jù)不同類型,路由處理和導(dǎo)航也不一樣
private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {final Context currentContext = null == context ? mContext : context;switch (postcard.getType()) {//是 ACTIVITY 數(shù)據(jù)填充到intent,并且調(diào)用 startActivitycase ACTIVITY:final Intent intent = new Intent(currentContext, postcard.getDestination());intent.putExtras(postcard.getExtras());// Set flags.int flags = postcard.getFlags();if (-1 != flags) {intent.setFlags(flags);} else if (!(currentContext instanceof Activity)) { // Non activity, need less one flag.intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);}// Set ActionsString action = postcard.getAction();if (!TextUtils.isEmpty(action)) {intent.setAction(action);}// Navigation in main looper.runInMainThread(new Runnable() {@Overridepublic void run() {startActivity(requestCode, currentContext, intent, postcard, callback);}});break;//PROVIDER類型,則直接返回其服務(wù)提供者case PROVIDER:return postcard.getProvider();//如果是BOARDCAST 、 CONTENT_PROVIDER 、 FRAGMENT,則創(chuàng)建其需要的實(shí)體,并填充數(shù)據(jù),返回對(duì)象 case BOARDCAST:case CONTENT_PROVIDER:case FRAGMENT:Class fragmentMeta = postcard.getDestination();try {Object instance = fragmentMeta.getConstructor().newInstance();if (instance instanceof Fragment) {((Fragment) instance).setArguments(postcard.getExtras());} else if (instance instanceof android.support.v4.app.Fragment) {((android.support.v4.app.Fragment) instance).setArguments(postcard.getExtras());}return instance;} catch (Exception ex) {logger.error(Consts.TAG, "Fetch fragment instance error, " + TextUtils.formatStackTrace(ex.getStackTrace()));}case METHOD:case SERVICE:default:return null;}return null;}
上面的初始化代碼其實(shí)就可以了解其原理,下面我們可以畫出時(shí)序圖,了解大致流程。
四、總結(jié)
ARouter 通過(guò) apt 技術(shù),生成保存路徑(路由path)和被注解(@Router)的組件類的映射關(guān)系的類,利用這些保存了映射關(guān)系的類,根據(jù)用戶的請(qǐng)求 postcard(明信片)尋找到要跳轉(zhuǎn)的目標(biāo)地址(class),使用 Intent 跳轉(zhuǎn)。
ARouter的重要性主要體現(xiàn)在以下幾個(gè)方面:
- 模塊化開發(fā):隨著軟件規(guī)模和復(fù)雜度的增加,越來(lái)越多的應(yīng)用程序采用模塊化開發(fā)方式。ARouter支持跨模塊的調(diào)用,簡(jiǎn)化了模塊間跳轉(zhuǎn)的復(fù)雜度,降低了耦合性,提升了整個(gè)應(yīng)用的可維護(hù)性和可擴(kuò)展性。
- 代碼解耦:在傳統(tǒng)的Activity跳轉(zhuǎn)方式中,一般是通過(guò)Intent來(lái)傳遞參數(shù),不同頁(yè)面之間的參數(shù)傳遞比較麻煩,還有可能導(dǎo)致代碼冗余。ARouter采用注解方式傳遞參數(shù),簡(jiǎn)化了代碼的編寫和閱讀。
- 動(dòng)態(tài)路由:路由是基于注解方式實(shí)現(xiàn)的,可以在代碼中動(dòng)態(tài)注冊(cè)和刪除路由。ARouter還支持路由重定向、降級(jí)等高級(jí)功能,可以根據(jù)不同的業(yè)務(wù)場(chǎng)景靈活處理路由邏輯。
- 統(tǒng)一管理:ARouter提供了統(tǒng)一管理路由配置的界面,可以直覽整個(gè)項(xiàng)目的路由規(guī)則,方便開發(fā)人員進(jìn)行維護(hù)和管理。
ARouter是一款非常實(shí)用的路由框架,可以幫助開發(fā)者在模塊化開發(fā)、代碼解耦、動(dòng)態(tài)路由和統(tǒng)一管理等方面提高開發(fā)效率和應(yīng)用質(zhì)量。
下面整理了《Android 架構(gòu)學(xué)習(xí)手冊(cè)》+《深入理解Gradle框架》學(xué)習(xí)筆記,根據(jù)自己學(xué)習(xí)中所做的一些筆錄來(lái)整的,主要也是方便后續(xù)好復(fù)習(xí)翻閱,省掉在去網(wǎng)上查找的時(shí)間,以免在度踩坑,如果大家有需要的可以直接 通過(guò)點(diǎn)擊此處↓↓↓ 進(jìn)行參考學(xué)習(xí):https://qr21.cn/CaZQLo?BIZ=ECOMMERCE
Android 架構(gòu)學(xué)習(xí)手冊(cè)
?
?