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

Android Jetpack Compose之確定重組范圍并優(yōu)化重組

這篇具有很好參考價(jià)值的文章主要介紹了Android Jetpack Compose之確定重組范圍并優(yōu)化重組。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

1.概述

Compose的重組是智能的,Composable函數(shù)在進(jìn)行重組時(shí)會(huì)盡可能的跳過(guò)不必要的重組,只對(duì)需要變化的UI進(jìn)行重組。那Compose是如何認(rèn)定UI需要變化呢?或者換句話說(shuō)Compose是如何確定重組的范圍呢。如果重組隨意的發(fā)生,那么對(duì)UI的性能會(huì)是一個(gè)很不穩(wěn)定的狀態(tài),時(shí)而好,時(shí)而壞。而且如果編寫的UI代碼有問(wèn)題,那么重組將會(huì)帶來(lái)狀態(tài)的混亂,導(dǎo)致UI顯示出錯(cuò)。所以弄清楚Compose重組的范圍確定才能更好的避免重組的坑,并且可以針對(duì)具體的范圍做優(yōu)化,所以本文將介紹如何確定Compose重組的范圍以及重組性能的優(yōu)化。

2.確定Composable重組的范圍

確定重組的范圍有助于我們更好的理解ComposeUI的性能優(yōu)化,下面我們先看一個(gè)例子:

    @Composable
    fun CounterDemo(){
        Log.d("zhongxj","范圍1=>運(yùn)行")
        var counter by remember { mutableStateOf(0) }
        Column {
            Log.d("zhongxj","范圍2=>運(yùn)行")
            Button(onClick = {
                Log.d("zhongxj","onButtonClick:點(diǎn)擊按鈕")
                counter ++
            }){
                Log.d("zhongxj","范圍3=>運(yùn)行")
                Text(text = "+")
            }

            Text(text = "$counter")
        }
    }

在上面的代碼中,我們依然使用計(jì)數(shù)器的例子來(lái)驗(yàn)證重組的范圍,我們?cè)诟鱾€(gè)可能發(fā)生重組的地方都打上了Log,當(dāng)點(diǎn)擊Button時(shí),計(jì)數(shù)器counter的狀態(tài)更新會(huì)觸發(fā)CounterDemo的重組,日志如下圖所示:

Android Jetpack Compose之確定重組范圍并優(yōu)化重組,Android,Jetpack compose,移動(dòng)開(kāi)發(fā),android jetpack,android,移動(dòng)開(kāi)發(fā),安卓,compose

從圖中我們可以看到, Log.d("zhongxj","范圍3=>運(yùn)行") 這行Log并沒(méi)有打,沒(méi)有打這行l(wèi)og的原因需要我們了解Compose重組的底層原理:

在Compose中,經(jīng)過(guò)Compose編譯器處理后的Composable函數(shù)在對(duì)State進(jìn)行讀取的同時(shí),能夠自動(dòng)建立關(guān)聯(lián),在運(yùn)行過(guò)程中,當(dāng)State變化時(shí)Compose會(huì)找到關(guān)聯(lián)的代碼塊并將其標(biāo)記為Invalid.在下一個(gè)渲染幀到來(lái)之前,Compose會(huì)觸發(fā)重組并且執(zhí)行invalid代碼塊,而Invalid代碼塊即為下一次重組的范圍。能夠被標(biāo)記為Invalid的代碼有2個(gè)兩個(gè)要求,一是被標(biāo)記為Invalid的代碼必須時(shí)非inline且沒(méi)有返回值的Composable函數(shù),二是無(wú)返回值的Lambda。

那么為啥參與重組的代碼塊必須是非inline的無(wú)返回值函數(shù)呢?因?yàn)閕nline函數(shù)在編譯期會(huì)在調(diào)用處展開(kāi),因此無(wú)法在下次重組時(shí)找到合適的調(diào)用入口,只能共享調(diào)用方的重組范圍。而有返回值的函數(shù)由于返回值會(huì)影響調(diào)用方,所以必須聯(lián)通調(diào)用方一起參與重組。因此inline的有返回值的函數(shù)不能作為Invalid代碼塊。

而了解了Compose的底層重組原理,我們就可以清楚的知道了只有受到State變化影響的代碼塊,才會(huì)參與到重組。不依賴State的代碼則不參與重組,這就是重組的最小化原則。

基于重組最小化原則,我們可以分析下我們計(jì)數(shù)器例子中的輸出結(jié)果,其實(shí)看了日志發(fā)現(xiàn) Log.d("zhongxj","范圍3=>運(yùn)行")這行日志沒(méi)有打,也就是說(shuō)這行日志所在的代碼塊并沒(méi)有參與重組,在范圍2的作用域中,我們看到了這行代碼Text(text = "$counter"),很明顯這行代碼依賴了counter狀態(tài),需要注意的是這行代碼并不是讀取counter值的意思,它的意思是在范圍2的作用域中讀取counter的值并傳入Text,所以范圍2是會(huì)參與重組的,日志就輸出了Log.d("zhongxj","范圍2=>運(yùn)行"),這時(shí)有讀者可能會(huì)發(fā)現(xiàn),按照重組最小化原則,那么訪問(wèn)counter的最小范圍應(yīng)該是:范圍2的作用域呀,為啥范圍1的日志也會(huì)被打印呢?這里需要回想下咱們之前講的:最小化范圍的定義必須是非inline的composable函數(shù)或者lambda。而Column組件是一個(gè)inline聲明的高階函數(shù):

Android Jetpack Compose之確定重組范圍并優(yōu)化重組,Android,Jetpack compose,移動(dòng)開(kāi)發(fā),android jetpack,android,移動(dòng)開(kāi)發(fā),安卓,compose

所以content內(nèi)部也會(huì)被展開(kāi)在調(diào)用處,所以范圍1和范圍2就共享了重組的范圍,所以輸出了Log.d("zhongxj","范圍1=>運(yùn)行")日志,假設(shè)將Column換成非inline的Composable,那么Log.d("zhongxj","范圍1=>運(yùn)行")將不會(huì)輸出,比如換成一個(gè)Card組件,讀者可以自行試一下。

需要注意的是,Button雖然沒(méi)有依賴counter,但是范圍2的重組會(huì)觸發(fā)Button的重新調(diào)用,所以 Log.d("zhongxj","onButtonClick:點(diǎn)擊按鈕") 也會(huì)輸出,但是其content內(nèi)部并沒(méi)有依賴counter,所以范圍3的日志: Log.d(“zhongxj”,“范圍3=>運(yùn)行”) 不會(huì)輸出。

補(bǔ)充說(shuō)明: Composable 函數(shù)觀察State變化并觸發(fā)重組是在被稱為”快照“的系統(tǒng)中完成的,所謂”快照“就是將被訪問(wèn)的狀態(tài)像拍照一樣保存下來(lái),當(dāng)狀態(tài)變化時(shí),通知相關(guān)的Composable應(yīng)用的最新?tīng)顟B(tài)。”快照“有利于對(duì)狀態(tài)管理進(jìn)行線程隔離,在多線程場(chǎng)景下的重組有重要的應(yīng)用

3.優(yōu)化重組的性能

經(jīng)過(guò)前面的分析,我沒(méi)了解到了Compose的重組是智能的,遵循范圍最小化原則,重組中執(zhí)行到的Composable只有在其參數(shù)發(fā)生變化時(shí),才會(huì)參與本次重組。

Compose 在執(zhí)行后會(huì)生成一棵視圖樹(shù),每個(gè)Composable對(duì)應(yīng)樹(shù)上的一個(gè)節(jié)點(diǎn),因此Composable 智能重組的本質(zhì)其實(shí)是從樹(shù)上尋找對(duì)應(yīng)位置的節(jié)點(diǎn)并與之進(jìn)行比較,如果節(jié)點(diǎn)未發(fā)生變化則不用更新。

另外需要注意的是,視圖樹(shù)的實(shí)際構(gòu)建過(guò)程比較復(fù)雜,Composable執(zhí)行過(guò)程中,先將生成的Composition狀態(tài)存入SlotTable,然后框架基于SlotTable生成LayoutNode樹(shù),并完成最終的界面渲染。所以謹(jǐn)慎的說(shuō),Composable的比較邏輯是發(fā)生在SlotTable中的。

3.1 Composable 位置索引

在重組的過(guò)程中,Composition上的節(jié)點(diǎn)可以完成增、刪、移動(dòng)、更新等多種變化,Compose編譯器會(huì)根據(jù)代碼調(diào)用位置,為Composable生成索引key,并且存入Composition,Composable在執(zhí)行過(guò)程中通過(guò)與Key的對(duì)比可以知道當(dāng)前應(yīng)該執(zhí)行何種操作。例如下面的示例代碼:

    Box {
            if (state) {
                val str = remember(Unit) { "call_site_1" }
                Text(text = str) // Text_of_call_site_1
            } else {
                val str = remember(Unit) { "call_site_2" }
                Text(text = str) // Text_of_call_site_2
            }
        }

如上面代碼所示:Composable中遇到if/else等條件語(yǔ)句時(shí),會(huì)插入startXXXGroup類似的代碼,并且通過(guò)添加索引Key識(shí)別節(jié)點(diǎn)的增減,上面的代碼中會(huì)根據(jù)state的不同顯示不同的Text,編譯器會(huì)為if和else分支分別建立索引,當(dāng)state由true變?yōu)閒alse時(shí),Box發(fā)生重組,通過(guò)key的判斷可知,else內(nèi)的代碼需要插入邏輯執(zhí)行,而if內(nèi)生成的節(jié)點(diǎn)需要被移除。

假設(shè)沒(méi)有編譯期的位置索引,而僅僅靠運(yùn)行時(shí)比較,首先執(zhí)行到 remember(Unit)時(shí),由于緩存原因仍然會(huì)返回當(dāng)前樹(shù)上存放的str,即call_site_1,接著執(zhí)行到Text_of_call_site_1,發(fā)現(xiàn)與當(dāng)前樹(shù)上的節(jié)點(diǎn)類型一樣,參數(shù)str也沒(méi)有變化,因此會(huì)判斷為無(wú)須重組,那么文本就無(wú)法得到更新

所以,綜上所述:Composable 在編譯期建立索引是保證其重組能夠智能且正確執(zhí)行的基礎(chǔ)。這個(gè)索引是根據(jù)Composable在靜態(tài)代碼中的被調(diào)用位置決定的。但是在某些場(chǎng)景中,Composable無(wú)法通過(guò)靜態(tài)代碼位置進(jìn)行索引,這時(shí)我們需要手動(dòng)添加索引,便于在重組中進(jìn)行比較

3.2 通過(guò)Key添加索引信息

假設(shè)我們現(xiàn)在需要給一個(gè)電影列表,然后展示電影的大致信息,代碼如下所示:

@Composable
    fun MoviesScreen(movies:List<Movie>){
        Column { 
            for (movie in movies){
                // showMoveCardInfo 無(wú)法在編譯期間進(jìn)行索引,只能根據(jù)運(yùn)行時(shí)的index進(jìn)行索引
                showMoveCardInfo(movie)
            }
        }
    }

如上面的代碼所示,基于Movie的名字展示電影的信息,此時(shí)無(wú)法基于代碼中的位置進(jìn)行索引,只能在運(yùn)行時(shí)基于index進(jìn)行索引。這樣的話索引會(huì)根據(jù)item的數(shù)量發(fā)生變化,導(dǎo)致無(wú)法準(zhǔn)確進(jìn)行比較。在這種情況下,當(dāng)重組發(fā)生時(shí),新插入的數(shù)據(jù)會(huì)和以前的第一個(gè)數(shù)據(jù)比較,以前的第一個(gè)數(shù)據(jù)會(huì)和第二個(gè)數(shù)據(jù)比較,然后以前的第二個(gè)數(shù)據(jù)會(huì)被當(dāng)作新數(shù)據(jù)插入。結(jié)果是所有的item都會(huì)發(fā)生重組,但是我們期望的行為是,只有新插入的數(shù)據(jù)需要重組,其他沒(méi)有變化的數(shù)據(jù)不應(yīng)該發(fā)生重組,所以我們可以使用key的方法為Composable在運(yùn)行時(shí)手動(dòng)添加一個(gè)索引,如下所示:

@Composable
    fun MoviesScreen(movies:List<Movie>){
        Column { 
            for (movie in movies){
               key(movie.id){ // 使用movie的唯一ID作為Composable的索引
                showMoveCardInfo(movie)
                }
            }
        }
    }

使用movie的ID傳入Composable做為唯一索引,當(dāng)插入新數(shù)據(jù)時(shí),之前對(duì)象的索引沒(méi)有被打亂,仍然可以發(fā)揮比較時(shí)的錨定作用,所以其他沒(méi)有發(fā)生變化的item就可以不用參與重組

3.3 使用注解@Stable優(yōu)化重組

Composable是基于參數(shù)的比較結(jié)果來(lái)決定是否重組,也就是說(shuō),只有當(dāng)參與比較的參數(shù)對(duì)象是穩(wěn)定的且equals返回true,才認(rèn)為是相等的。Kotlin中常見(jiàn)的基本類型(Boolean、Int、Long、Float、Char) String,Lambda表達(dá)式都可以認(rèn)為式穩(wěn)定的,因?yàn)槎际遣豢勺冾愋汀K运麄兊膮?shù)比較的結(jié)果都式可信的。但是假如參數(shù)是可變類型,那么比較的結(jié)果將是不可信的。

data class Mutabledata(var data:String)

    @Composable
    fun MutableDemo(){
        var mutable = remember { Mutabledata("walt") }

        var state by remember { mutableStateOf(false) }
        if(state){
            mutable.data = "zxj"
        }

        Button(onClick = {state = true}){
           showText(mutable)
        }
    }
    @Composable
    fun ShowText(mutable:MutableData){
     Text(text = mutable.data) // 會(huì)隨著state的變化而變化
    }

在上面的代碼中,MutableData是一個(gè)不穩(wěn)定的對(duì)象,因?yàn)樗幸粋€(gè)Var類型的變量data,當(dāng)點(diǎn)擊按鈕改變狀態(tài)時(shí),mutable會(huì)修改data,對(duì)于ShowText來(lái)說(shuō),參數(shù)mutable在狀態(tài)改變前后都指向同一個(gè)對(duì)象,因此僅僅靠equals判斷會(huì)認(rèn)為參數(shù)沒(méi)有發(fā)生變化,但實(shí)際上測(cè)試發(fā)現(xiàn)ShowText函數(shù)發(fā)生了重組,所以Mutabledata參數(shù)類型是不穩(wěn)定的,equals結(jié)果不可信。

所以對(duì)于一些默認(rèn)不被認(rèn)為是穩(wěn)定類型的,比如interface或者list等集合類,如果能夠確保其在運(yùn)行時(shí)的穩(wěn)定,可以為其添加@State注解,編譯器會(huì)將這些類型視為穩(wěn)定類型,從而發(fā)揮只能重組的作用,提升性能。代碼如下所示:

@Stable
interface UiState<T>{
    val value:T?
    val exception:Throwable?
    val hasError:Boolean
        get() = exception != null
}

注意: 被添加為@Statble的普通父類、密封類、接口等其派生子類也會(huì)被認(rèn)為時(shí)穩(wěn)定的

Android 學(xué)習(xí)筆錄

Android 性能優(yōu)化篇:https://qr18.cn/FVlo89
Android Framework底層原理篇:https://qr18.cn/AQpN4J
Android 車載篇:https://qr18.cn/F05ZCM
Android 逆向安全學(xué)習(xí)筆記:https://qr18.cn/CQ5TcL
Android 音視頻篇:https://qr18.cn/Ei3VPD
Jetpack全家桶篇(內(nèi)含Compose):https://qr18.cn/A0gajp
OkHttp 源碼解析筆記:https://qr18.cn/Cw0pBD
Kotlin 篇:https://qr18.cn/CdjtAF
Gradle 篇:https://qr18.cn/DzrmMB
Flutter 篇:https://qr18.cn/DIvKma
Android 八大知識(shí)體:https://qr18.cn/CyxarU
Android 核心筆記:https://qr21.cn/CaZQLo
Android 往年面試題錦:https://qr18.cn/CKV8OZ
2023年最新Android 面試題集:https://qr18.cn/CgxrRy
Android 車載開(kāi)發(fā)崗位面試習(xí)題:https://qr18.cn/FTlyCJ
音視頻面試題錦:https://qr18.cn/AcV6Ap文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-729033.html

到了這里,關(guān)于Android Jetpack Compose之確定重組范圍并優(yōu)化重組的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(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)文章

  • Android Jetpack Compose — Slider滑動(dòng)條

    Android Jetpack Compose — Slider滑動(dòng)條

    ? ? ? ? 在Android Jetpack Compose中,Slider(滑動(dòng)條)是一個(gè)常用的用戶界面控件,它允許通過(guò)滑動(dòng)條來(lái)選擇一個(gè)范圍或數(shù)值。Slider控件非常適用于調(diào)整音量、亮度、進(jìn)度等需要連續(xù)調(diào)整的場(chǎng)景。 一、Slider的屬性 ????????Slider是Android Jetpack Compose中的一個(gè)控件,用于實(shí)現(xiàn)滑動(dòng)條

    2024年02月11日
    瀏覽(93)
  • 探索Android Jetpack Compose的Surface組件

    探索Android Jetpack Compose的Surface組件

    隨著聲明性 UI 框架 Jetpack Compose 的出現(xiàn),Android 開(kāi)發(fā)變得更加簡(jiǎn)潔和直觀。在這篇博客中,我們將深入探討其中的一項(xiàng)基本構(gòu)建塊 —— Surface 組件,了解它如何影響 UI 的顯示和設(shè)計(jì)。 一、Jetpack Compose和Surface組件 二、Surface組件的基本使用 三、影響Surface的屬性 一、Jetpack Co

    2024年02月11日
    瀏覽(95)
  • Android Jetpack Compose之RadioGroup的使用

    Android Jetpack Compose之RadioGroup的使用

    Android Jetpack Compose是一個(gè)現(xiàn)代化的UI工具包,幫助開(kāi)發(fā)者以聲明式的方式構(gòu)建出美觀且功能強(qiáng)大的Android應(yīng)用。在本文中,我們將詳細(xì)介紹其中的一個(gè)重要組件—— RadioGroup 。 一. RadioGroup簡(jiǎn)介 Jetpack Compose中并沒(méi)有像傳統(tǒng)View系統(tǒng)中那樣直接提供 RadioGroup ,但我們可以很方便地通

    2024年02月06日
    瀏覽(101)
  • 現(xiàn)代化 Android 開(kāi)發(fā):Jetpack Compose 最佳實(shí)踐

    現(xiàn)代化 Android 開(kāi)發(fā):Jetpack Compose 最佳實(shí)踐

    作者:古哥E下 如果一直關(guān)注 Compose 的發(fā)展的話,可以明顯感受到 2022 年和 2023 年的 Compose 使用討論的聲音已經(jīng)完全不一樣了, 2022 年還多是觀望,2023 年就有很多團(tuán)隊(duì)開(kāi)始采納 Compose 來(lái)進(jìn)行開(kāi)發(fā)了。不過(guò)也有很多同學(xué)接觸了下 Compose,然后就放棄了。要么使用起來(lái)賊特么不順手

    2024年02月17日
    瀏覽(105)
  • Android Jetpack Compose中使用字段驗(yàn)證的方法

    Android Jetpack Compose中使用字段驗(yàn)證的方法

    數(shù)據(jù)驗(yàn)證是創(chuàng)建健壯且用戶友好的Android應(yīng)用程序的關(guān)鍵部分。隨著現(xiàn)代UI工具包Jetpack Compose的引入,處理字段驗(yàn)證變得更加高效和直觀。在這篇文章中,我們將探討如何在Android應(yīng)用中使用Jetpack Compose進(jìn)行字段驗(yàn)證。 字段驗(yàn)證是確保用戶在各種輸入字段中輸入的數(shù)據(jù)符合特定

    2024年02月11日
    瀏覽(98)
  • Android Jetpack Compose實(shí)現(xiàn)輪播圖效果

    Android Jetpack Compose實(shí)現(xiàn)輪播圖效果

    在最近思索如何使用Compose方式改進(jìn)我的開(kāi)源TMDB電影列表應(yīng)用程序的主屏幕時(shí),一個(gè)激動(dòng)人心的概念浮現(xiàn)在我的腦海中——為什么不整合一個(gè)吸引人的輪播圖來(lái)展示即將上映的電影呢?在本文中,我將分享我的開(kāi)發(fā)和實(shí)現(xiàn)自定義輪播圖的經(jīng)歷,提供涉及不同步驟的見(jiàn)解。 首先

    2024年02月08日
    瀏覽(128)
  • 對(duì)于Android開(kāi)發(fā),我們?yōu)楹我獙W(xué)Jetpack Compose?

    對(duì)于Android開(kāi)發(fā),我們?yōu)楹我獙W(xué)Jetpack Compose?

    Jetpack Compose 是用于構(gòu)建原生 Android 界面的新工具包。它可簡(jiǎn)化并加快 Android 上的界面開(kāi)發(fā),使用更少的代碼、強(qiáng)大的工具和直觀的 Kotlin API,快速讓應(yīng)用生動(dòng)而精彩。Compose 使用全新的組件——可組合項(xiàng) (Composable) 來(lái)布局界面,使用修飾符 (Modifier) 來(lái)配置可組合項(xiàng)。 為何Jetp

    2024年02月10日
    瀏覽(97)
  • Android全新UI框架之Jetpack Compose入門基礎(chǔ)

    Android全新UI框架之Jetpack Compose入門基礎(chǔ)

    Jetpack Compose是什么 如果有跨端開(kāi)發(fā)經(jīng)驗(yàn)的同學(xué),理解和學(xué)習(xí)compose可能沒(méi)有那么大的壓力。簡(jiǎn)單地說(shuō),compose可以讓Android的原生開(kāi)發(fā)也可以使用類似rn的jsx的語(yǔ)法來(lái)開(kāi)發(fā) UI界面 。以往,我們開(kāi)發(fā)Android原生頁(yè)面的時(shí)候,通常是在xml中畫(huà)相關(guān)的UI控件,然后在activity中通過(guò)findViewB

    2024年02月21日
    瀏覽(25)
  • Android 在xml 布局中如何嵌套 Jetpack Compose

    最近在項(xiàng)目開(kāi)發(fā)的過(guò)程中需要用到 Jetpack Compose,之前沒(méi)有接觸過(guò)Compose,所以項(xiàng)目一直沒(méi)有用到Compose。通過(guò)查看官網(wǎng)發(fā)現(xiàn)Compose上手比較快,但是準(zhǔn)備比較復(fù)雜的布局要轉(zhuǎn)換成Compose 不是一件容易的事情。那有沒(méi)有可能只是對(duì)成熟的項(xiàng)目中的xml 布局中的某一部分進(jìn)行改造,讓其

    2024年04月10日
    瀏覽(86)
  • Android Jetpack Compose之底部導(dǎo)航欄的實(shí)現(xiàn)

    Android Jetpack Compose之底部導(dǎo)航欄的實(shí)現(xiàn)

    寫過(guò)一段Android jetpack compose 界面的小伙伴應(yīng)該都用過(guò)Compose的腳手架 Scaffold ,利用它我們可以很快的實(shí)現(xiàn)一個(gè)現(xiàn)代APP的主流界面架構(gòu),即一個(gè)帶頂部導(dǎo)航欄和底部導(dǎo)航欄的界面架構(gòu),我們基于這個(gè)架構(gòu)可以快速的搭建出我們想要的頁(yè)面效果。而今天的文章就是要介紹如何實(shí)現(xiàn)

    2024年03月23日
    瀏覽(102)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包