聊聊 Jetpack Compose

本文章首發於公衆號 Android丨Kotlin,歡迎關注!編程

Hello 你們好,我是 wanbo,久等了,今天咱們來聊聊 Jetpack Compose。markdown

在 Beta 版發佈以後,我先去閱讀了官方的文檔,而後在 Youtube 上面官方發佈的 Jetpack Compose 的相關視頻也所有看了一遍,以後又去參加了官方組織的 #AndroidDevChalleng 作了實際的上手體驗。架構

今年主要是圍繞 Jetpack Compose ,一共是四周的挑戰內容,每週會有一個不同的題目,目的是讓你從不一樣維度熟悉 Jetpack Compose,如今已經進展到了第二週,有興趣的朋友能夠去關注一下。app

我如今對 Jetpack Compose 的理解也比較有限,還不是很深刻,可是在讀完官方的文檔以後,我以爲 Jetpack Compose 有不少在設計上讓我感到很驚豔的地方,因此就火燒眉毛的想和你們分享一下。ide

1. 先來聊聊我我的對 Compose 的使用建議

你能夠對它保持關注,官方有任何學習內容看一眼就好了,有個大概印象寫個 Demo 玩玩就能夠了,千萬別激進的在正式項目裏使用它。函數

我以前寫過兩個 iOS 的獨立項目,在最開始我都是用的 SwiftUI 去寫的,寫的時候很爽,畢竟是新東西,好奇心以及成就感是很是強的,但無一例外,我以後都用傳統的命令式 UI 把它們重寫了。學習

由於坑實在是太多了,大部分時間我都在解 Bug ,並且不少時候我都不知道是它自己的 bug 仍是我寫出的 bug,固然這也和 iOS 自己閉源的緣由有關。優化

在 Jetpack Compose 開發本身的新 feature 以前,它首要的任務,是把現有的 View 組件所有翻譯一遍,翻譯也是有一個過程的,首先會把 View 表層的東西翻譯完,好比如何寫一個 TextView,如何寫一個 Layout,如何寫一個列表,在以後是翻譯 View 裏層的東西,好比 View 的各類 Listener,各類 Event。ui

我認爲可能要到 Release 2.0 的時候,裏層的大多數功能,纔會支持完善,看不到的功能缺失,會出現不少不可預估的問題,而後你上網去搜如何解決 XXX 問題,發現你們都和你同樣懵逼,不知道怎麼辦,由於這自己就是它的 bug,只有官方去修復和支持才能完全解決。lua

還有一個須要注意的點,就是生態,在生態不豐富以前,你只能選擇官方支持的一些解決方案,遇到須要特殊自定義的功能,可能會增長你好幾倍的開發成本。

因此,想要在正式項目裏使用,必定要謹慎。

2. 傳統的 View 體系和 Jetpack Compose 的差別

差別主要在兩方面:UI 的構建和 UI 的刷新。

在維基百科中,命令式編程的定義是這樣的:經過使用改變程序狀態的語句,來實現某些功能和效果。聲明式編程的定義是:在不描述其控制流程的狀況下表達了計算的邏輯。

用白話來說就是

命令式編程須要告訴系統每一步要作什麼,具體該怎麼作,經過這樣的一種流程實現咱們想要的功能。

聲明式編程則是隱藏了怎麼作這個流程,你只須要操做一些基本元素,經過組合方式,把你想要的效果搭建出來就行了。

使用聲明式 UI 編寫界面能夠極大的減小代碼量,同時也提升了容錯率,整個 UI 構建邏輯也變得更加清晰、易讀。

另外一個差別點在於 UI 的刷新層面

傳統的 View 體系中,是經過調用 View 的某些 set 方法來更新 UI 的狀態,這是一個手動更新 UI 的過程,這個過程的維護性一般會隨着 UI 複雜度的增長而增長,很是容易出錯。

在 Compose 裏動態的 UI 是和數據綁定的,當數據發生變化的時候,能夠自動更新 UI 的狀態,徹底不須要手動更新,即便 UI 很複雜,咱們也只須要專一於數據的更新邏輯就能夠了。

從 UI 的構建到 UI 的刷新,其實都是一個由複雜變簡單的過程,讓開發者能夠更專一於業務邏輯的開發。

3. Compose 的核心設計理念

咱們仍是從 UI 的構建和刷新這兩個層面來聊,但這一部分要引入兩個新名詞:組合和重組

UI 的構建

在 Compose 中,View 再也不是某個對象,是以 @Composable 標記的方法存在。

UI 的構建是經過組合不一樣的 @Composable 元素實現,例如咱們要實現一個文本列表,能夠選擇 Column 元素(縱向列表),而後在內部聲明 Text 元素,就能夠很是快的實現。全部的 UI 效果均可以經過 Compose 中內置的基本元素組合實現。

@Composable 元素是互相獨立的,不存在繼承關係,這和傳統的命令式編程是徹底不同的,元素的差別性也是經過組合實現的,經過組合不一樣的內置基本元素來實現一個新的元素結構。

Compose 有一個很是核心的類 Modifier,能夠理解爲元素加強或元素修飾,每個 @Composable 元素均可以接受一個 Modifier,經過定義不一樣的 Modifier 來修改元素的實際表現形式。

推薦你們經過元素組合的方式實現一個新的自定義元素,而後傳入不一樣的 Modifier 而達到自定義 View 的複用效果。

UI 的刷新

在 Compose 中,UI 的刷新是經過從新渲染生成整個屏幕實現的,這是全部聲明式 UI 刷新頁面的工做原理。

可是 Compose 會根據數據的變化,僅針對須要改變的元素作必要的修改,經過改變數據而從新生成組合 UI 這一過程稱爲重組。當數據更新了,雖然是從整個屏幕開始從新渲染,但與數據修改無關的元素,會保持以前生成的實例,由於 @Composable 方法渲染是很是快的、冪等且無反作用。

很是重要的一點就是冪等,冪等的意思是指可使用相同參數重複執行,並能得到相同結果的函數。這些函數不會影響系統狀態,也不用擔憂重複執行會對系統形成改變。說白了就是與數據修改無關的 @Composable 元素在屏幕從新渲染的過程當中不會被重組。

整個重組的過程是很是智能的,Compose 編譯器會在 @Composable 元素初始化的時候,對每個元素作標記,而後根據數據是否修改來智能的選擇須要被重組的元素。

咱們也能夠增長額外的輔助信息,幫助 Compose 編譯器作更精準的判斷,一個典型的例子就是在動態列表中,若是咱們在最後添加一條數據,那麼編譯器就是認爲前面的數據是沒有任何修改的,僅重組最後一條元素。

可是當咱們在 index == 0 的位置,插入一條數據,那麼編譯器會認爲整個列表都被修改了,由於在它的默認標記中會記錄位置信息,在 0 的位置插入數據,意味着整個列表都須要被重組。

這個時候,咱們能夠給列表的內容增長 key 的標記,一般是惟一不變的 id,告訴編譯器還須要判斷 id 是否變化,此時編譯器僅會重組第一條元素,以後的元素依舊使用以前生成好的實例。

在 Compose 中 UI 刷新的惟一方法就是重組,是否重組的判斷條件就是與 @Composable 元素綁定的數據是否發生了變化。

重組須要注意的地方

重組意味着系統會從新調用 @Composable 元素方法的執行,而重組可能會隨時且很是頻繁的發生,全部的 @Composable 方法的執行都是亂序和並行的,這一點咱們須要注意的。

因此到 @Composable 方法裏面,任何一個 Local 變量,任何一個動態計算方法,任何一個更新數據的邏輯,都須要仔細考慮,否則就會出現不可預估的錯誤。

可能在重組過程當中,Local 變量會失效,動態計算方法會調用不少次,這裏實際上是一個大坑,但願 Android Studio 之後能夠在 @Composable 方法裏有嚴格的代碼檢查,幫助你們在寫的時候就能夠檢查出一些潛在的錯誤。

3. 官方推薦的 UI 與數據的組合方式

一種相似於單項數據流的處理方式

動態的 @Composable 元素由上層傳遞的數據所控制,交互事件經過 Block 的方式再傳回上層,經過在上層更新數據,從而實現 UI 的動態更新。數據傳遞是自上而下的,交互事件的傳遞是自下而上的。

按照這種邏輯,咱們須要在 ViewModel 中定義可變的數據,同時定義好修改數據的方法,把數據自上而下傳遞到實際的 UI 中,而後將 UI 的交互事件向上傳遞,經過執行最上層 ViewModel 中修改數據的方法,更新數據。

但這樣其實會引起一個新的問題,當咱們的 UI 特別複雜的時候, @Composable 方法的參數可能會變得很是多。

這時候就須要你去使用不一樣的內置基本元素來實現一個新的元素結構,經過組合的方式,優化代碼的結構,相似這樣。

最後

雖然一眼看上去 Jetpack Compose 是一個全新的東西,但認真閱讀了文檔以後,其實都很好理解,重點是 Compose 加速了整個 Android 開發的速度,由複雜變簡單,讓咱們能夠專一於業務邏輯上的實現。

包括這幾年 Jetpack 的快速迭代,目的也是同樣的,並且 Compose 和以前 Jetpack 中的那一套架構設計規則是能夠無縫使用的,只是把咱們以前寫 UI 的邏輯改變了。

Jetpack Compose 確定不是 Android UI 開發的最終形態,但絕對是 Android 技術生態上的一個巨大的進步。

固然仍是那句話,想要在正式項目裏使用,必定要謹慎,再等等。

今天的分享就到這裏,Compose 內容其實不少,一篇文章確實也沒法徹底涵蓋到,你們有其餘關心的點,能夠繼續在評論區留言,下期我專門寫一篇答疑文章~

歡迎關注公衆號 Android丨Kotlin

相關文章
相關標籤/搜索