国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【KRouter】一個(gè)簡(jiǎn)單且輕量級(jí)的Kotlin Routing框架

這篇具有很好參考價(jià)值的文章主要介紹了【KRouter】一個(gè)簡(jiǎn)單且輕量級(jí)的Kotlin Routing框架。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

【KRouter】一個(gè)簡(jiǎn)單且輕量級(jí)的Kotlin Routing框架,Kotlin進(jìn)階,kotlin,開(kāi)發(fā)語(yǔ)言,android

【KRouter】一個(gè)簡(jiǎn)單且輕量級(jí)的Kotlin Routing框架

KRouter(Kotlin-Router)是一個(gè)簡(jiǎn)單而輕量級(jí)的Kotlin路由框架。

具體來(lái)說(shuō),KRouter是一個(gè)通過(guò)URI來(lái)發(fā)現(xiàn)接口實(shí)現(xiàn)類(lèi)的框架。它的使用方式如下:

val homeScreen = KRouter.route<Screen>("screen/home?name=zhangke")

之所以這樣做,是因?yàn)樵谑褂肰oyager一段時(shí)間后,我發(fā)現(xiàn)模塊之間的通信不夠靈活,需要一些配置,而且使用DeepLink有點(diǎn)奇怪,所以我更喜歡使用路由來(lái)實(shí)現(xiàn)模塊之間的通信,于是我開(kāi)發(fā)了這個(gè)庫(kù)。

這個(gè)庫(kù)主要通過(guò)KSP、ServiceLoader和反射來(lái)實(shí)現(xiàn)。

使用方法

上述代碼基本上就是使用的全部?jī)?nèi)容。

如前所述,這是用于發(fā)現(xiàn)接口實(shí)現(xiàn)類(lèi)并通過(guò)URI匹配目標(biāo)的庫(kù),因此我們首先需要定義一個(gè)接口。

interface Screen

然后我們有一個(gè)包含許多獨(dú)立模塊的項(xiàng)目,這些模塊實(shí)現(xiàn)了這個(gè)接口,每個(gè)模塊都不同,我們需要通過(guò)它們各自的路由(即URI)來(lái)區(qū)分它們。

// HomeModule
@Destination("screen/home")
class HomeScreen(@Router val router: String = "") : Screen

// ProfileModule
@Destination("screen/profile")
class ProfileScreen : Screen {
    @Router
    lateinit var router: String
}

現(xiàn)在我們有兩個(gè)獨(dú)立的模塊,它們各自擁有自己的屏幕(Screens),并且它們都有自己的路由地址。

val homeScreen = KRouter.route<Screen>("screen/home?name=zhangke")
val profileScreen = KRouter.route<Screen>("screen/profile?name=zhangke")

現(xiàn)在,您可以通過(guò)KRouter獲取這兩個(gè)對(duì)象,并且這些對(duì)象中的路由屬性將被分配給對(duì)KRouter.route的特定調(diào)用的路由。

現(xiàn)在,您可以在HomeScreenProfileScreen中獲取通過(guò)URI傳遞的參數(shù),并且可以使用這些參數(shù)進(jìn)行一些初始化和其他操作。

@Destination

@Destination 注解用于標(biāo)記目的地(Destination),包含兩個(gè)參數(shù):

  • route:目的地的唯一標(biāo)識(shí)路由地址,必須是 URI 類(lèi)型的字符串,不需要包含查詢(xún)參數(shù)。
  • type:目的地的接口。如果類(lèi)只有一個(gè)父類(lèi)或接口,您無(wú)需設(shè)置此參數(shù),它可以自動(dòng)推斷。但如果類(lèi)有多個(gè)父類(lèi)或接口,您需要通過(guò) type 參數(shù)明確指定。

需要特別注意的是,被 @Destination 注解標(biāo)記的類(lèi)必須包含一個(gè)無(wú)參數(shù)構(gòu)造函數(shù),否則 ServiceLoader 無(wú)法創(chuàng)建對(duì)象。對(duì)于 Kotlin 類(lèi),您還需要確保構(gòu)造函數(shù)的每個(gè)輸入?yún)?shù)都具有默認(rèn)值。

@Router

@Router 注解用于指定目的地類(lèi)的哪個(gè)屬性用于接收傳入的路由參數(shù),該屬性必須是字符串類(lèi)型。

使用此注解標(biāo)記的屬性將自動(dòng)分配一個(gè)值,或者您可以不設(shè)置注解。例如,在上述示例中,當(dāng)創(chuàng)建 HomeScreen 對(duì)象時(shí),其 router 字段的值將自動(dòng)設(shè)置為 screen/home?name=zhangke。

特別要注意,如果被@Router注解的屬性不在構(gòu)造函數(shù)中,那么該屬性必須聲明為可修改的,即在 Kotlin 中應(yīng)為 var 修飾的可變屬性。

KRouter 是一個(gè) Kotlin Object 類(lèi),它只包含一個(gè)函數(shù):

inline fun <reified T : Any> route(router: String): T?

此函數(shù)接受一個(gè)泛型類(lèi)型和一個(gè)路由地址。路由地址可以包含或不包含查詢(xún)參數(shù),但在匹配目的地時(shí),查詢(xún)參數(shù)將被忽略。匹配成功后,將使用此 URI 構(gòu)造對(duì)象,并將 URI 傳遞給目標(biāo)對(duì)象中的 @router 注解字段。

集成

首先,您需要在項(xiàng)目中集成 KSP。

https://kotlinlang.org/docs/ksp-overview.html

然后,添加以下依賴(lài)項(xiàng):

// 模塊的 build.gradle.kts
implementation("com.github.0xZhangKe.KRouter:core:0.1.5")
ksp("com.github.0xZhangKe.KRouter:compiler:0.1.5")

由于使用了 ServiceLoader,您還需要設(shè)置 SourceSet。

// 模塊的 build.gradle.kts
kotlin {
    sourceSets.main {
        resources.srcDir("build/generated/ksp/main/resources")
    }
}

可能還需要添加 JitPack 倉(cāng)庫(kù):

maven { setUrl("https://jitpack.io") }

工作原理

正如前面所提到的,KRouter 主要通過(guò) ServiceLoader + KSP + 反射來(lái)實(shí)現(xiàn)。

這個(gè)框架由兩個(gè)主要部分組成:編譯階段和運(yùn)行時(shí)階段。

KSP 插件
與 KSP 插件相關(guān)的代碼位于編譯器模塊中。

KSP 插件的主要任務(wù)是根據(jù) Destination 注解生成 ServiceLoader 的服務(wù)文件。

KSP 代碼的其余部分基本相同,主要工作包括首先配置服務(wù)文件,然后根據(jù)注解獲取類(lèi),最后通過(guò) Visitor 進(jìn)行迭代。您可以直接查看 KRouterVisitor 來(lái)了解更多細(xì)節(jié)。

override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
    val superTypeName = findSuperType(classDeclaration)
    writeService(superTypeName, classDeclaration)
}

visitClassDeclaration 方法主要有兩個(gè)主要功能,第一是獲取父類(lèi),第二是編寫(xiě)或創(chuàng)建服務(wù)文件。

流程首先是獲取指定類(lèi)型的父類(lèi),如果沒(méi)有父類(lèi),且只有一個(gè)父類(lèi)時(shí),可以直接返回,否則會(huì)引發(fā)異常。

// find super-type by type parameter
val routerAnnotation = classDeclaration.requireAnnotation<Destination>()
val typeFromAnnotation = routerAnnotation.findArgumentTypeByName("type")
        ?.takeIf { it != badTypeName }

// find single-type
if (classDeclaration.superTypes.isSingleElement()) {
    val superTypeName = classDeclaration.superTypes
        .iterator()
        .next()
        .typeQualifiedName
        ?.takeIf { it != badSuperTypeName }
    if (!superTypeName.isNullOrEmpty()) {
        return superTypeName
    }
}

一旦獲取到父類(lèi),我們需要?jiǎng)?chuàng)建一個(gè)文件,其文件名以接口或抽象類(lèi)的權(quán)限作為所需的 ServiceLoader 文件名。

然后,我們將已實(shí)現(xiàn)類(lèi)的權(quán)限名稱(chēng)寫(xiě)入該文件。

val resourceFileName = ServicesFiles.getPath(superTypeName)
val serviceClassFullName = serviceClassDeclaration.qualifiedName!!.asString()
val existsFile = environment.codeGenerator
    .generatedFile
    .firstOrNull { generatedFile ->
        generatedFile.canonicalPath.endsWith(resourceFileName)
    }
if (existsFile != null) {
    val services = existsFile.inputStream().use { ServicesFiles.readServiceFile(it) }
    services.add(serviceClassFullName)
    existsFile.outputStream().use { ServicesFiles.writeServiceFile(services, it) }
} else {
    environment.codeGenerator.createNewFile(
        dependencies = Dependencies(aggregating = false, serviceClassDeclaration.containingFile!!),
        packageName = "",
        fileName = resourceFileName,
        extensionName = "",
    ).use {
        ServicesFiles.writeServiceFile(setOf(serviceClassFullName), it)
    }
}

KRouter主要有三個(gè)關(guān)鍵功能:

  1. 通過(guò)ServiceLoader獲取接口的所有實(shí)現(xiàn)類(lèi)。
  2. 將特定的目標(biāo)類(lèi)與URI進(jìn)行匹配。
  3. 從URI構(gòu)建目標(biāo)類(lèi)對(duì)象。
    第一件事非常簡(jiǎn)單:
inline fun <reified T> findServices(): List<T> {
    val clazz = T::class.java
    return ServiceLoader.load(clazz, clazz.classLoader).iterator().asSequence().toList()
}

一旦你獲取到它,你就可以開(kāi)始與URL進(jìn)行匹配。

這個(gè)匹配的方式是獲取每個(gè)目標(biāo)類(lèi)的Destination注解中的路由字段,然后將其與路由進(jìn)行比較。

fun findServiceByRouter(
    serviceClassList: List<Any>,
    router: String,
): Any? {
    val routerUri = URI.create(router).baseUri
    val service = serviceClassList.firstOrNull {
        val serviceRouter = getRouterFromClassAnnotation(it::class)
        if (serviceRouter.isNullOrEmpty().not()) {
            val serviceUri = URI.create(serviceRouter!!).baseUri
            serviceUri == routerUri
        } else {
            false
        }
    }
    return service
}

private fun getRouterFromClassAnnotation(targetClass: KClass<*>): String? {
    val routerAnnotation = targetClass.findAnnotation<Destination>() ?: return null
    return routerAnnotation.router
}

匹配策略是忽略查詢(xún)字段,只需通過(guò)baseUri進(jìn)行匹配即可。

接下來(lái)的步驟是創(chuàng)建對(duì)象。有兩種情況需要考慮:

第一種情況是@Router注解位于構(gòu)造函數(shù)中,在這種情況下,需要再次使用構(gòu)造函數(shù)創(chuàng)建對(duì)象。

第二種情況是@Router注解位于普通屬性中。在這種情況下,可以直接使用ServiceLoader創(chuàng)建的對(duì)象,然后將值分配給它。

如果@Router注解位于構(gòu)造函數(shù)中,您可以首先獲取routerParameter,然后使用PrimaryConstructor重新創(chuàng)建對(duì)象。

private fun fillRouterByConstructor(router: String, serviceClass: KClass<*>): Any? {
    val primaryConstructor = serviceClass.primaryConstructor
        ?: throw IllegalArgumentException("KRouter Destination class must have a Primary-Constructor!")
    val routerParameter = primaryConstructor.parameters.firstOrNull { parameter ->
        parameter.findAnnotation<Router>() != null
    } ?: return null
    if (routerParameter.type != stringKType) errorRouterParameterType(routerParameter)
    return primaryConstructor.callBy(mapOf(routerParameter to router))
}

如果它是一個(gè)普通的變量屬性,首先獲取屬性,然后進(jìn)行一些類(lèi)型權(quán)限和其他檢查,然后調(diào)用setter方法分配值。

private fun fillRouterByProperty(
    router: String,
    service: Any,
    serviceClass: KClass<*>,
): Any? {
    val routerProperty = serviceClass.findRouterProperty() ?: return null
    fillRouterToServiceProperty(
        router = router,
        service = service,
        property = routerProperty,
    )
    return service
}

private fun KClass<*>.findRouterProperty(): KProperty<*>? {
    return declaredMemberProperties.firstOrNull { property ->
        val isRouterProperty = property.findAnnotation<Router>() != null
        isRouterProperty
    }
}

private fun fillRouterToServiceProperty(
    router: String,
    service: Any,
    property: KProperty<*>,
) {
    if (property !is KMutableProperty<*>) throw IllegalArgumentException("@Router property must be non-final!")
    if (property.visibility != KVisibility.PUBLIC) throw IllegalArgumentException("@Router property must be public!")
    val setter = property.setter
    val propertyType = setter.parameters[1]
    if (propertyType.type != stringKType) errorRouterParameterType(propertyType)
    property.setter.call(service, router)
}

上面是關(guān)于KRouter的全部?jī)?nèi)容,希望對(duì)你有所幫助!

GitHub

https://github.com/0xZhangKe/KRouter文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-701236.html

到了這里,關(guān)于【KRouter】一個(gè)簡(jiǎn)單且輕量級(jí)的Kotlin Routing框架的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶(hù)投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 教你使用PHP實(shí)現(xiàn)一個(gè)輕量級(jí)HTML模板引擎

    教你使用PHP實(shí)現(xiàn)一個(gè)輕量級(jí)HTML模板引擎

    ??作者簡(jiǎn)介,黑夜開(kāi)發(fā)者,全棧領(lǐng)域新星創(chuàng)作者?,2023年6月csdn上海賽道top4。多年電商行業(yè)從業(yè)經(jīng)驗(yàn),對(duì)系統(tǒng)架構(gòu),數(shù)據(jù)分析處理等大規(guī)模應(yīng)用場(chǎng)景有豐富經(jīng)驗(yàn)。 ??本文已收錄于PHP專(zhuān)欄:PHP進(jìn)階實(shí)戰(zhàn)教程。 ??另有專(zhuān)欄PHP入門(mén)基礎(chǔ)教程,希望各位大佬多多支持??。 在 W

    2024年02月15日
    瀏覽(101)
  • OpenHarmony實(shí)戰(zhàn)開(kāi)發(fā)-如何實(shí)現(xiàn)一個(gè)輕量級(jí)輸入法應(yīng)用。

    OpenHarmony實(shí)戰(zhàn)開(kāi)發(fā)-如何實(shí)現(xiàn)一個(gè)輕量級(jí)輸入法應(yīng)用。

    ? 本示例使用inputMethodEngine實(shí)現(xiàn)一個(gè)輕量級(jí)輸入法應(yīng)用kikaInput,支持在運(yùn)行OpenHarmony OS的智能終端上。 使用說(shuō)明 1.使用hdc shell aa start ability -a InputMethod -b cn.openharmony.inputmethodchoosedialog命令拉起切換輸入法彈窗,點(diǎn)擊kikainput切換輸入法到當(dāng)前應(yīng)用。 2.點(diǎn)擊應(yīng)用中的編輯框,拉起

    2024年04月24日
    瀏覽(89)
  • golang一個(gè)輕量級(jí)基于內(nèi)存的kv存儲(chǔ)或緩存

    golang一個(gè)輕量級(jí)基于內(nèi)存的kv存儲(chǔ)或緩存 go-cache是一個(gè)輕量級(jí)的基于內(nèi)存的key:value 儲(chǔ)存組件,類(lèi)似于memcached,適用于在單機(jī)上運(yùn)行的應(yīng)用程序。 它的主要優(yōu)點(diǎn)是,本質(zhì)上是一個(gè)具有過(guò)期時(shí)間的線程安全map[string]interface{}。interface的結(jié)構(gòu)決定了它不需要序列化?;趦?nèi)存的特性

    2024年02月02日
    瀏覽(99)
  • PikVM:輕量級(jí)虛擬化解決方案,讓云計(jì)算更簡(jiǎn)單

    項(xiàng)目地址:https://gitcode.com/pikvm/pikvm PikVM 是一個(gè)創(chuàng)新的、輕量級(jí)的虛擬化平臺(tái),旨在簡(jiǎn)化云計(jì)算環(huán)境的部署和管理。它基于KVM(Kernel-based Virtual Machine),但提供了一種更加簡(jiǎn)潔且易于使用的接口,適合開(kāi)發(fā)者、運(yùn)維人員以及對(duì)虛擬化技術(shù)感興趣的任何人。 PikVM 的核心理念是“

    2024年04月16日
    瀏覽(97)
  • python輕量級(jí)web框架flask初探,搭建網(wǎng)站原來(lái)這么簡(jiǎn)單

    python輕量級(jí)web框架flask初探,搭建網(wǎng)站原來(lái)這么簡(jiǎn)單

    ?? 歡迎大家來(lái)到景天科技苑?? ???? 養(yǎng)成好習(xí)慣,先贊后看哦~???? ?? 作者簡(jiǎn)介:景天科技苑 ??《頭銜》:大廠架構(gòu)師,華為云開(kāi)發(fā)者社區(qū)專(zhuān)家博主,阿里云開(kāi)發(fā)者社區(qū)專(zhuān)家博主,CSDN新星創(chuàng)作者,掘金優(yōu)秀博主,51CTO博客專(zhuān)家等。 ??《博客》:Python全棧,前后端開(kāi)

    2024年03月19日
    瀏覽(575)
  • LLM-Client一個(gè)輕量級(jí)的LLM集成工具

    LLM-Client一個(gè)輕量級(jí)的LLM集成工具

    大型語(yǔ)言模型(llm)已經(jīng)徹底改變了我們與文本交互的方式,OpenAI、Google、AI21、HuggingfaceHub、Anthropic和眾多開(kāi)源模型提供了不同的功能和優(yōu)勢(shì)。但是每個(gè)模型都有其獨(dú)特的體系結(jié)構(gòu)、api和兼容性需求,集成這些模型是一項(xiàng)耗時(shí)且具有挑戰(zhàn)性的任務(wù)。 所以這時(shí)候LangChain就解決了這

    2024年02月11日
    瀏覽(98)
  • C++輕量級(jí)跨平臺(tái)桌面GUI庫(kù)FLTK的簡(jiǎn)單使用

    C++輕量級(jí)跨平臺(tái)桌面GUI庫(kù)FLTK的簡(jiǎn)單使用

    C++的跨平臺(tái)桌面GUI庫(kù)有很多,大體上分成兩種流派:retained mode和immediate mode。 其中前者是主流的桌面GUI機(jī)制框架,包括:Qt、wxwidgets、gtk、juce等 后者是一些游戲引擎編輯器常用的GUI機(jī)制框架,包括:imgui、nanogui等 使用這些框架都支持構(gòu)建在windows、mac、linux上面能運(yùn)行的桌面

    2024年02月08日
    瀏覽(87)
  • 用go設(shè)計(jì)開(kāi)發(fā)一個(gè)自己的輕量級(jí)登錄庫(kù)/框架吧

    幾乎每個(gè)項(xiàng)目都會(huì)有登錄,退出等用戶(hù)功能,而登錄又不單僅僅是登錄,我們要考慮很多東西。 token該怎么生成?生成什么樣的? 是在Cookie存token還是請(qǐng)求頭存token?讀取的時(shí)候怎么讀??? 允許同一個(gè)賬號(hào)被多次登錄嗎?多次登錄他們的token是一樣的?還是不一樣的? 登錄也

    2024年02月03日
    瀏覽(91)
  • 【表達(dá)式引擎】簡(jiǎn)單高效的輕量級(jí)Java表達(dá)式引擎:Aviator

    【表達(dá)式引擎】簡(jiǎn)單高效的輕量級(jí)Java表達(dá)式引擎:Aviator

    Aviator 是一個(gè)高性能、、輕量級(jí)的表達(dá)式引擎,支持表達(dá)式動(dòng)態(tài)求值。其設(shè)計(jì)目標(biāo)為輕量級(jí)和高性能,相比于 Groovy 和 JRuby 的笨重, Aviator 就顯得更加的小巧。與其他的輕量級(jí)表達(dá)式引擎不同,其他的輕量級(jí)表達(dá)式引擎基本都是通過(guò)解釋代碼的方式來(lái)運(yùn)行,而 Aviator 則是直接

    2024年02月09日
    瀏覽(98)
  • SimSearch:一個(gè)輕量級(jí)的springboot項(xiàng)目索引構(gòu)建工具,實(shí)現(xiàn)快速模糊搜索

    大部分項(xiàng)目都會(huì)涉及模糊搜索功能,而實(shí)現(xiàn)模糊搜索一般分為兩個(gè)派系: like簡(jiǎn)約派系 搜索引擎派系 對(duì)于較為大型的項(xiàng)目來(lái)說(shuō),使用Solr、ES或者M(jìn)ilvus之類(lèi)的引擎是比較流行的選擇了(效果只能說(shuō)優(yōu)秀),而對(duì)于中小型項(xiàng)目,如果考慮這些較為重型的引擎,就意味著開(kāi)發(fā)成本和

    2024年02月02日
    瀏覽(30)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包