2.編程思想

Jetpack Compose 是一個適用于 Android 的新式聲明性界面工具包稽坤。Compose 提供聲明性 API,可在不以命令方式改變前端視圖的情況下呈現(xiàn)應用界面赫编,從而使編寫和維護應用界面變得更加容易夏志。

聲明性編程范式

長期以來垒拢,Android 視圖層次結構一直可以表示為界面 widget 樹。由于應用的狀態(tài)會因用戶交互等因素而發(fā)生變化荣恐,因此界面層次結構需要進行更新以顯示當前數(shù)據(jù)液斜。最常見的界面更新方式是使用?findViewById()?等函數(shù)遍歷樹,并通過調用?button.setText(String)叠穆、container.addChild(View)?或?img.setImageBitmap(Bitmap)?等方法更改節(jié)點少漆。這些方法會改變 widget 的內部狀態(tài)。

手動操縱視圖會提高出錯的可能性痹束。如果一條數(shù)據(jù)在多個位置呈現(xiàn)检疫,很容易忘記更新顯示它的某個視圖。此外祷嘶,當兩項更新以出人意料的方式發(fā)生沖突時屎媳,也很容易造成異常狀態(tài)夺溢。例如,某項更新可能會嘗試設置剛剛從界面中移除的節(jié)點的值烛谊。一般來說风响,軟件維護的復雜性會隨著需要更新的視圖數(shù)量而增長。

在過去的幾年中丹禀,整個行業(yè)已開始轉向聲明性界面模型状勤,該模型大大簡化了與構建和更新界面關聯(lián)的工程任務。該技術的工作原理是在概念上從頭開始重新生成整個屏幕双泪,然后僅執(zhí)行必要的更改持搜。此方法可避免手動更新有狀態(tài)視圖層次結構的復雜性。

重新生成整個屏幕所面臨的一個難題是焙矛,在時間葫盼、計算能力和電池用量方面可能成本高昂。為了減少在這方面耗費的資源村斟,Compose 會智能地選擇在任何給定時間需要重新繪制界面的哪些部分贫导。

簡單的可組合函數(shù)

使用 Compose,可以通過定義一組接受數(shù)據(jù)而發(fā)出界面元素的可組合函數(shù)來構建界面蟆盹。一個簡單的示例:


關于此函數(shù)孩灯,有幾點值得注意:

此函數(shù)帶有?@Composable?注釋。所有可組合函數(shù)都必須帶有此注釋逾滥;此注釋可告知 Compose 編譯器:此函數(shù)旨在將數(shù)據(jù)轉換為界面峰档。

此函數(shù)接受數(shù)據(jù)∠痪啵可組合函數(shù)可以接受一些參數(shù)面哥,這些參數(shù)可讓應用邏輯描述界面。在本例中毅待,可組合函數(shù)接受一個?String,因此它可以按名稱問候用戶归榕。

此函數(shù)可以在界面中顯示文本尸红。為此,它會調用?Text()?可組合函數(shù)刹泄,該函數(shù)實際上會創(chuàng)建文本界面元素外里。可組合函數(shù)通過調用其他可組合函數(shù)來發(fā)出界面層次結構特石。

此函數(shù)不會返回任何內容盅蝗。發(fā)出界面的 Compose 函數(shù)不需要返回任何內容,因為它們描述所需的屏幕狀態(tài)姆蘸,而不是構造界面 widget墩莫。

此函數(shù)快速芙委、冪等且沒有附帶效應。

使用同一參數(shù)多次調用此函數(shù)時狂秦,它的行為方式相同灌侣,并且它不使用其他值,如全局變量或對?random()?的調用裂问。

此函數(shù)描述界面而沒有任何副作用侧啼,如修改屬性或全局變量。

一般來說堪簿,所有可組合函數(shù)都應使用這些屬性來編寫痊乾。

聲明性范式轉變

在許多面向對象的命令式界面工具包中,可以通過實例化 widget 樹來初始化界面椭更,通常通過膨脹 XML 布局文件來實現(xiàn)此目的符喝。每個 widget 都維護自己的內部狀態(tài),并且提供 getter 和 setter 方法甜孤,允許應用邏輯與 widget 進行交互协饲。

在 Compose 的聲明性方法中,widget 相對無狀態(tài)缴川,并且不提供 setter 或 getter 函數(shù)茉稠。實際上,widget 不會以對象形式提供把夸。通過調用帶有不同參數(shù)的同一可組合函數(shù)來更新界面而线。這使得向架構模式(如?ViewModel)提供狀態(tài)變得很容易。然后恋日,可組合項負責在每次可觀察數(shù)據(jù)更新時將當前應用狀態(tài)轉換為界面膀篮。


應用邏輯為頂級可組合函數(shù)提供數(shù)據(jù)。該函數(shù)通過調用其他可組合函數(shù)來使用這些數(shù)據(jù)描述界面岂膳,將適當?shù)臄?shù)據(jù)傳遞給這些可組合函數(shù)誓竿,并沿層次結構向下傳遞數(shù)據(jù)。

當用戶與界面交互時谈截,界面會發(fā)起?onClick?等事件筷屡。這些事件應通知應用邏輯,應用邏輯隨后可以改變應用的狀態(tài)簸喂。當狀態(tài)發(fā)生變化時毙死,系統(tǒng)會使用新數(shù)據(jù)再次調用可組合函數(shù)。這會導致重新繪制界面元素喻鳄,此過程稱為“重組”扼倘。


用戶與界面元素進行了交互,導致觸發(fā)一個事件除呵。應用邏輯響應該事件再菊,然后系統(tǒng)根據(jù)需要使用新參數(shù)自動再次調用可組合函數(shù)爪喘。

動態(tài)內容

由于可組合函數(shù)是用 Kotlin 而不是 XML 編寫的,因此它們可以像其他任何 Kotlin 代碼一樣動態(tài)袄简。例如腥放,假設想要構建一個界面,用來問候一些用戶:


此函數(shù)接受名稱的列表绿语,并為每個用戶生成一句問候語秃症。可組合函數(shù)可能非常復雜吕粹≈指蹋可以使用?if?語句來確定是否要顯示特定的界面元素,可以使用循環(huán)匹耕,可以調用輔助函數(shù)聚请。它擁有底層語言的全部靈活性。這種強大的功能和靈活性是 Jetpack Compose 的主要優(yōu)勢之一稳其。

重組

在命令式界面模型中驶赏,如需更改某個 widget,可以在該 widget 上調用 setter 以更改其內部狀態(tài)既鞠。在 Compose 中煤傍,可以使用新數(shù)據(jù)再次調用可組合函數(shù)。這樣做會導致函數(shù)進行重組 -- 系統(tǒng)會根據(jù)需要使用新數(shù)據(jù)重新繪制函數(shù)發(fā)出的 widget嘱蛋。Compose 框架可以智能地僅重組已更改的組件蚯姆。

例如,假設有以下可組合函數(shù)洒敏,它用于顯示一個按鈕:


每次點擊該按鈕時龄恋,調用方都會更新?clicks?的值。Compose 會再次調用 lambda 與?Text?函數(shù)以顯示新值凶伙;此過程稱為“重組”郭毕。不依賴于該值的其他函數(shù)不會進行重組。

重組是指在輸入更改時再次調用可組合函數(shù)的過程镊靴。當函數(shù)的輸入更改時铣卡,會發(fā)生這種情況。當 Compose 根據(jù)新輸入重組時偏竟,它僅調用可能已更改的函數(shù)或 lambda,而跳過其余函數(shù)或 lambda敞峭。通過跳過所有未更改參數(shù)的函數(shù)或 lambda踊谋,Compose 可以高效地重組。

切勿依賴于執(zhí)行可組合函數(shù)所產生的附帶效應旋讹,因為可能會跳過函數(shù)的重組殖蚕。如果這樣做轿衔,可能會遇到奇怪且不可預測的行為。附帶效應是指對應用的其余部分可見的任何更改睦疫。例如害驹,以下操作全部都是危險的附帶效應:

寫入共享對象的屬性

更新?ViewModel?中的可觀察項

更新共享偏好設置

可組合函數(shù)可能會像每一幀一樣頻繁地重新執(zhí)行,例如在呈現(xiàn)動畫時蛤育⊥鸸伲可組合函數(shù)應快速執(zhí)行,以避免在播放動畫期間出現(xiàn)卡頓瓦糕。如果需要執(zhí)行成本高昂的操作(例如從共享偏好設置讀取數(shù)據(jù))底洗,請在后臺協(xié)程中執(zhí)行,并將值結果作為參數(shù)傳遞給可組合函數(shù)咕娄。

例如亥揖,以下代碼會創(chuàng)建一個可組合項以更新?SharedPreferences?中的值。該可組合項不應從共享偏好設置本身讀取或寫入圣勒,于是此代碼將讀取和寫入操作移至后臺協(xié)程中的?ViewModel费变。應用邏輯會使用回調傳遞當前值以觸發(fā)更新。



以下是使用 Compose 時需要注意的一些事項:

????可組合函數(shù)可以按任何順序執(zhí)行圣贸。

????可組合函數(shù)可以并行執(zhí)行挚歧。

? ? 重組會跳過盡可能多的可組合函數(shù)和 lambda。

? ? 重組是樂觀的操作旁趟,可能會被取消昼激。

????可組合函數(shù)可能會像動畫的每一幀一樣非常頻繁地運行。

可組合函數(shù)可以按任何順序執(zhí)行

如果看一下可組合函數(shù)的代碼锡搜,可能會認為這些代碼按其出現(xiàn)的順序運行橙困。但其實未必是這樣。如果某個可組合函數(shù)包含對其他可組合函數(shù)的調用耕餐,這些函數(shù)可以按任何順序運行凡傅。Compose 可以選擇識別出某些界面元素的優(yōu)先級高于其他界面元素,因而首先繪制這些元素肠缔。

可組合函數(shù)可以并行運行

Compose 可以通過并行運行可組合函數(shù)來優(yōu)化重組夏跷。這樣一來,Compose 就可以利用多個核心明未,并以較低的優(yōu)先級運行可組合函數(shù)(不在屏幕上)槽华。

這種優(yōu)化意味著,可組合函數(shù)可能會在后臺線程池中執(zhí)行趟妥。如果某個可組合函數(shù)對?ViewModel?調用一個函數(shù)猫态,則 Compose 可能會同時從多個線程調用該函數(shù)。

為了確保應用正常運行,所有可組合函數(shù)都不應有附帶效應亲雪,而應通過始終在界面線程上執(zhí)行的?onClick?等回調觸發(fā)附帶效應勇凭。

調用某個可組合函數(shù)時,調用可能發(fā)生在與調用方不同的線程上义辕。這意味著虾标,應避免使用修改可組合 lambda 中的變量的代碼,既因為此類代碼并非線程安全代碼灌砖,又因為它是可組合 lambda 不允許的附帶效應璧函。

重組會跳過盡可能多的內容

如果界面的某些部分無效,Compose 會盡力只重組需要更新的部分周崭。這意味著柳譬,它可以跳過某些內容以重新運行單個按鈕的可組合項,而不執(zhí)行界面樹中在其上面或下面的任何可組合項续镇。

每個可組合函數(shù)和 lambda 都可以自行重組美澳。同樣,執(zhí)行所有可組合函數(shù)或 lambda 都應該沒有附帶效應摸航。當需要執(zhí)行附帶效應時制跟,應通過回調觸發(fā)。

重組是樂觀的操作

只要 Compose 認為某個可組合項的參數(shù)可能已更改酱虎,就會開始重組雨膨。重組是樂觀的操作,也就是說读串,Compose 預計會在參數(shù)再次更改之前完成重組聊记。如果某個參數(shù)在重組完成之前發(fā)生更改,Compose 可能會取消重組恢暖,并使用新參數(shù)重新開始排监。

取消重組后,Compose 會從重組中舍棄界面樹杰捂。如有任何附帶效應依賴于顯示的界面舆床,則即使取消了組合操作,也會應用該附帶效應嫁佳。這可能會導致應用狀態(tài)不一致挨队。

確保所有可組合函數(shù)和 lambda 都冪等且沒有附帶效應,以處理樂觀的重組蒿往。

可組合函數(shù)可能會非常頻繁地運行

在某些情況下盛垦,可能會針對界面動畫的每一幀運行一個可組合函數(shù)。如果該函數(shù)執(zhí)行成本高昂的操作(例如從設備存儲空間讀取數(shù)據(jù))瓤漏,可能會導致界面卡頓情臭。

例如省撑,如果 widget 嘗試讀取設備設置赌蔑,它可能會在一秒內讀取這些設置數(shù)百次俯在,這會對應用的性能造成災難性的影響。

如果可組合函數(shù)需要數(shù)據(jù)娃惯,它應為相應的數(shù)據(jù)定義參數(shù)跷乐。然后,可以將成本高昂的工作移至組成操作線程之外的其他線程趾浅,并使用?mutableStateOf?或?LiveData?將相應的數(shù)據(jù)傳遞給 Compose愕提。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市皿哨,隨后出現(xiàn)的幾起案子浅侨,更是在濱河造成了極大的恐慌,老刑警劉巖证膨,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件如输,死亡現(xiàn)場離奇詭異,居然都是意外死亡央勒,警方通過查閱死者的電腦和手機不见,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來崔步,“玉大人稳吮,你說我怎么就攤上這事【簦” “怎么了灶似?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長瑞你。 經常有香客問我酪惭,道長,這世上最難降的妖魔是什么捏悬? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任撞蚕,我火速辦了婚禮,結果婚禮上过牙,老公的妹妹穿的比我還像新娘甥厦。我一直安慰自己,他們只是感情好寇钉,可當我...
    茶點故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布刀疙。 她就那樣靜靜地躺著,像睡著了一般扫倡。 火紅的嫁衣襯著肌膚如雪谦秧。 梳的紋絲不亂的頭發(fā)上竟纳,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天,我揣著相機與錄音疚鲤,去河邊找鬼锥累。 笑死,一個胖子當著我的面吹牛集歇,可吹牛的內容都是我干的桶略。 我是一名探鬼主播,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼诲宇,長吁一口氣:“原來是場噩夢啊……” “哼际歼!你這毒婦竟也來了?” 一聲冷哼從身側響起姑蓝,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤鹅心,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后纺荧,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體旭愧,經...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年虐秋,在試婚紗的時候發(fā)現(xiàn)自己被綠了榕茧。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡客给,死狀恐怖用押,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情靶剑,我是刑警寧澤蜻拨,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站桩引,受9級特大地震影響缎讼,放射性物質發(fā)生泄漏。R本人自食惡果不足惜坑匠,卻給世界環(huán)境...
    茶點故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一血崭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧厘灼,春花似錦夹纫、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至闪朱,卻和暖如春月匣,著一層夾襖步出監(jiān)牢的瞬間钻洒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工锄开, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留素标,地道東北人。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓院刁,卻偏偏與公主長得像糯钙,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子退腥,可洞房花燭夜當晚...
    茶點故事閱讀 45,107評論 2 356

推薦閱讀更多精彩內容