Flutter路由管理代码这么长长长长长,阿里工程师怎么高效解决?(实用)
背景:
在flutter的業(yè)務(wù)開(kāi)發(fā)過(guò)程中,flutter側(cè)會(huì)逐漸豐富自己的路由管理。一個(gè)輕量的路由管理本質(zhì)上是頁(yè)面標(biāo)識(shí)(或頁(yè)面路徑)與頁(yè)面實(shí)例的映射。本文基于dart注解提供了一個(gè)輕量路由管理方案。?
 不論是在native與flutter的混合工程,還是純flutter開(kāi)發(fā)的工程,當(dāng)我們實(shí)現(xiàn)一個(gè)輕量路由的時(shí)候一般會(huì)有以下幾種方法:
做映射時(shí)較差的實(shí)現(xiàn)是通過(guò)if-else的邏輯判斷把url映射到對(duì)應(yīng)的widget實(shí)例上,
這樣做的弊端比較明顯:?
 1)每個(gè)映射的維護(hù)影響全局映射配置的穩(wěn)定性,每次維護(hù)映射管理時(shí)需要腦補(bǔ)所有的邏輯分支.?
 2)無(wú)法做到頁(yè)面的統(tǒng)一抽象,頁(yè)面的構(gòu)造器和構(gòu)造邏輯被開(kāi)發(fā)者自定義.?
 3)映射配置無(wú)法與頁(yè)面聯(lián)動(dòng),把頁(yè)面級(jí)的配置進(jìn)行中心化的維護(hù),導(dǎo)致維護(hù)責(zé)任人缺失.
稍微好一點(diǎn)的是將映射關(guān)系通過(guò)一個(gè)配置信息和一個(gè)工廠方法來(lái)表現(xiàn)
在flutter側(cè)這種做法仍然比較麻煩,首先是問(wèn)題3仍然存在,其次是由于flutter目前不支持反射,必須有一個(gè)類(lèi)似工廠方法的方式來(lái)創(chuàng)建頁(yè)面實(shí)例。?
 為了解決以上的問(wèn)題,我們需要一套能在頁(yè)面級(jí)使用、自動(dòng)維護(hù)映射的方案,注解就是一個(gè)值得嘗試的方向。我們的路由注解方案annotation_route(github地址:https://github.com/alibaba-flutter/annotation_route)?應(yīng)運(yùn)而生,整個(gè)注解方案的運(yùn)行系統(tǒng)如圖所示:?
 讓我們從dart注解開(kāi)始,了解這套系統(tǒng)的運(yùn)作。
dart注解
注解,實(shí)際上是代碼級(jí)的一段配置,它可以作用于編譯時(shí)或是運(yùn)行時(shí),由于目前flutter不支持運(yùn)行時(shí)的反射功能,我們需要在編譯期就能獲取到注解的相關(guān)信息,通過(guò)這些信息來(lái)生成一個(gè)自動(dòng)維護(hù)的映射表。那我們要做的,就是在編譯時(shí)通過(guò)分析dart文件的語(yǔ)法結(jié)構(gòu),找到文件內(nèi)的注解塊和注解的相關(guān)內(nèi)容,對(duì)注解內(nèi)容進(jìn)行收集,最后生成我們想要的映射表,這套方案的構(gòu)想如圖示:?
 在調(diào)研中發(fā)現(xiàn),dart的部分內(nèi)置庫(kù)加速了這套方案的落地。
source_gen
dart提供了build、analyser、source_gen這三個(gè)庫(kù),其中source_gen利用build庫(kù)和analyser庫(kù),給到了一層比較好的注解攔截的封裝。從注解功能的角度來(lái)看,這三個(gè)庫(kù)分別給到了如下的功能:
- build庫(kù):整套資源文件的處理
 - analyser庫(kù):對(duì)dart文件生成完備的語(yǔ)法結(jié)構(gòu)
 - source_gen庫(kù):提供注解元素的攔截?
這里簡(jiǎn)要介紹下source_gen和它的上下游,先看看我們捋出來(lái)的它注解相關(guān)的類(lèi)圖: 
source_gen的源頭是build庫(kù)提供的Builder基類(lèi),該類(lèi)的作用是讓使用者自定義正在處理的資源文件,它負(fù)責(zé)提供資源文件信息,同時(shí)提供生成新資源文件的方法。source_gen從build庫(kù)提供的Builder類(lèi)中派生出了一個(gè)自己的builder,同時(shí)自定義了一套生成器Generator的抽象,派生出來(lái)的builder接受Generator類(lèi)的集合,然后收集Generator的產(chǎn)出,最后生成一份文件,不同的派生builder對(duì)generator的處理各異。這樣source_gen就把一個(gè)文件的構(gòu)造過(guò)程交給了自己定義的多個(gè)Generator,同時(shí)提供了相對(duì)build庫(kù)而言比較友好的封裝。?
 在抽象的生成器Generator基礎(chǔ)上,source_gen提供了注解相關(guān)的生成器GeneratorForAnnotation,一個(gè)注解生成器實(shí)例會(huì)接受一個(gè)指定的注解類(lèi)型,由于analyser提供了語(yǔ)法節(jié)點(diǎn)的抽象元素Element和其metadata字段,即注解的語(yǔ)法抽象元素ElementAnnotation,注解生成器即可通過(guò)檢查每個(gè)元素的metadata類(lèi)型是否匹配聲明的注解類(lèi)型,從而篩選出被注解的元素及元素所在上下文的信息,然后將這些信息包裝給使用者,我們就可以利用這些信息來(lái)完成路由注解。
annotation_route
在了解了source_gen之后,我們開(kāi)始著手自己的注解解析方案annotation_route?
 剛開(kāi)始介入時(shí),我們遇到了幾個(gè)問(wèn)題:
在一番思索后我們有了如下產(chǎn)出
 首先將注解分成兩類(lèi),一類(lèi)用于注解頁(yè)面@ARoute,另一類(lèi)用于注解使用者自己的router@ARouteRoot。routeBuilder擁有RouteGenerator實(shí)例,RouteGenerator實(shí)例,負(fù)責(zé)@ARoute注解;routeWriteBuilder擁有RouteWriterGenerator實(shí)例,負(fù)責(zé)@ARouteRoot注解。通過(guò)build庫(kù)支持的配置文件build.yaml,控制兩類(lèi)builder的構(gòu)造順序,在routeBuilder執(zhí)行完成后去執(zhí)行routeWriteBuilder,這樣我們就能準(zhǔn)確的在所有頁(yè)面注解掃描完成后開(kāi)始生成自己的配置文件。?
 在注解解析工程中,對(duì)于@ARoute注解的頁(yè)面,通過(guò)RouteGenerator將其配置信息交給擁有靜態(tài)存儲(chǔ)空間的Collector處理,同時(shí)將其輸出內(nèi)容設(shè)為null,即不會(huì)生成對(duì)應(yīng)的文件。在@ARoute注解的所有頁(yè)面掃描完成后,RouteWriteGenerator則會(huì)調(diào)用Writer,它從Collector中提取信息,并生成最后的配置文件。對(duì)于使用者,我們提供了一層友好的封裝,在使用annotation_route配置到工程后,我們的路由代碼發(fā)生了這樣的變化:?
 使用前:
使用后:
import 'package:annotation_route/route.dart';class MyPageOption {String url;Map<String, dynamic> query;MyPageOption(this.url, this.query);}class Router {ARouteInternal internal = ARouteInternalImpl();Widget pageFromUrlAndQuery(String urlString, Map<String, dynamic> query) {ARouteResult routeResult = internal.findPage(ARouteOption(url: urlString, params: query), MyPageOption(urlString, query));if(routeResult.state == ARouteResultState.FOUND) {return routeResult.widget;}return DefaultWidget;}}目前該方案已在閑魚(yú)app內(nèi)穩(wěn)定運(yùn)行,我們提供了基礎(chǔ)的路由參數(shù),隨著flutter業(yè)務(wù)場(chǎng)景越來(lái)越復(fù)雜,我們也會(huì)在注解的自由度上進(jìn)行更深的探索。
?
原文鏈接
 本文為云棲社區(qū)原創(chuàng)內(nèi)容,未經(jīng)允許不得轉(zhuǎn)載。
總結(jié)
以上是生活随笔為你收集整理的Flutter路由管理代码这么长长长长长,阿里工程师怎么高效解决?(实用)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
                            
                        - 上一篇: (Python)零起步数学+神经网络入门
 - 下一篇: 聊聊安卓折叠屏给交互设计和开发带来的变化