發表時間:2019.11.7android
在前不久的 Android Dev Summit '19 上,Jetpack Compose 終於發佈了一個可直接得到的預覽版。如今的版本仍是 0.1.0-dev02,處於很是早期的版本,官方也再三強調很是有可能產生變化且沒法用於生產環境。不過我認爲這是簡單瞭解一下 Compose 的好時機。有備而無患。git
首先來了解一下如今嘗試 Compose 所須要的環境:github
好的,這篇文章就到此爲止吧。編程
等等!寫都寫了,我仍是再多寫一點吧。網絡
演這麼一出其實也是爲了說明,Compose 真的還處於很早期的階段,估計還須要很長一段路才能真正在項目中實際使用上。但早鳥多少能嚐到些甜頭。但願各位能經過簡單的瞭解,預判一下之後的開發趨勢,趁早規劃,適時投資。數據結構
同時因爲 Compose 還處於極可能發生不少變化的狀態,因此本文也不許備過多拘泥於使用的細節,而是從更爲大局的層面上介紹一下 Compose。固然,筆者本人經驗和眼界極爲有限,真知灼見是沒有的,但願起到拋磚引玉的做用。框架
請記得下載一個最新的 Android Studio,須要 4.0 版本,在發文時這意味着你須要使用 canary channel 版本的。編輯器
開始新建一個項目,會發現多了一個 Empty Compose Activity 的選項,選擇它,各類依賴會爲你配置好。那麼一個 hello world 會是這個樣子的:ide
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyApp()
}
}
}
@Composable
fun MyApp() {
Text("Hello world!")
}
複製代碼
好的,你已經知道了 Compose 的基礎知識,如今能夠嘗試用它來構建各類界面了。函數
請先慢着動手。若是去看官網的入門教程,你所獲得的核心內容的確就是這樣。因爲文檔及教程還很不完善,這裏我建議,出門左轉學習一下 Flutter。
這不是一句玩笑話。Compose 在控件的使用以及組合上,跟 Flutter 更爲相近,而跟 Android 以前的那套 UI 沒有太大的關係。使用 Layout Inspector 這個工具來查看 Compose 編寫的應用,能夠看到 Activity 內是一個 AndroidComposeView 包含了不少 RepaintBoundaryView。而沒有使用原先就有的 TextView 等控件。
假如你只接觸過 Android 的 UI 編程,可能須要一段時間來熟悉而後轉變原先的思惟。雖然 Compose 自己還很不完善,但這種聲明式的編程範式(declarative programming)能夠經過學習 React 或者 Flutter 等 UI 框架未雨綢繆一番。
關於聲明式編程稍後再提,我仍是繼續談一下一些常見的情形。
在佈局上,首先會教會你使用 Column 和 Row,可以對應代替 LinearLayout;FrameLayout 也換成了 Stack。若是你對 main axis、cross axis 還比較陌生,如上所說,能夠嘗試學習一下 React 和 Flutter。
視頻中提到,Compose 對 ConstraintLayout 的支持還正在進行中。因此能夠猜想還在對於現有的佈局控件,之後應該仍是會添加支持的。
大多數應用都逃不了網絡請求 + 列表展現!
Compose 提供了 VerticalScroller 和 HorizontalScroller 來生成列表,在使用上與 RecyclerView 是徹底不一樣的體驗:
@Composable
fun MyApp() {
VerticalScroller {
Column {
repeat(20) {
Row(mainAxisSize = LayoutSize.Expand) {
Container(height = 48.dp) {
Text("Item $it", modifier = Spacing(left = 16.dp))
}
}
}
}
}
}
複製代碼
事實上,Scroller 與 ScrollView 更接近,只提供了一個滾動的功能,並沒提到有對 View 進行回收複用。
@Composable
fun Greeting(name: String) {
MaterialTheme {
Surface(color = Color.White) {
Text(text = "Hello $name!", style = +themeTextStyle { h5 })
}
}
}
複製代碼
以上代碼添加了 Material 的主題。
在我看來,這種方式比使用 XML 那套繁瑣、不直觀、缺少文檔的方法要好太多。固然,也可能只是由於我菜。
Android Studio 4.0 還提供了一個名爲 Live Preview 的功能來預覽 Compose 的效果。經過給 Compose 函數添加 @Preview
註解來預覽該函數的效果。這個函數必須是無參的,並且能夠給註解傳遞不一樣的參數來預覽各類不一樣狀況下(不一樣主題不一樣屏幕大小等)的界面。
功能是好功能,但代碼發生變更後,必需要從新 build 後才能更新預覽,如今效率還比較低。
最後談談當狀態(數據)發生變化後,Compose 如何響應。
@Model
class State(var count: Int = 0)
@Composable
fun MyApp() {
val state = State()
MaterialTheme {
Stack {
aligned(Alignment.Center) {
Button("${state.count} clicks", {
state.count++
})
}
}
}
}
複製代碼
上面這段代碼,放置了一個按鈕,每按一次按鈕上的計數就會 +1。代碼裏並無對 State 進行監聽,而後再對 UI 進行更新。而是在 State 類上添加了 Model
註解,Compose 自動進行 UI 的更新(官方稱之爲 recompose)。
你或許會想:哦,setState()
。
Android 已經十年,設備的變化很是大,也涌現出不少心的開發技術和思想,但用來開發 UI 的工具卻還依舊停留在十年前。很多控件已通過時並且揹負了太多歷史包袱,從新開始或許是更好的選擇。
開發 UI 須要編寫 XML 佈局,經過代碼加載,可能還須要經過 XML 來定義 style,爲了編寫一個界面要作的工做太多了。並且考慮到 Activity 和 Fragment,須要顧及的就更多了。若是要自定義一個 View,要作什麼工做?我想「自定義 View」這幾個字,都能嚇退一批人吧。
而且大量 UI 工具與系統的版本綁定,新功能新修復沒法及時讓開發者和用戶受益。Material design?Who cares?那是 5.0 以上才大部分支持的東西,更別提 shape theming 了。
原先的控件使用了一些只有官方能使用的黑魔法,也就是 hidden API。Compose 將徹底在公開的 API 上進行構建,官方使用的廣大的普通開發者也可以使用。
插點私貨。我偶爾會看着隔壁 Flutter 流下羨慕的淚水。它提供了大量官方的控件,應對各類場景,並且在各類系統版本上提供統一的行爲。而我卻須要滿世界找非官方的實現,一個個查看是否知足個人需求,是否還在維護,是否須要本身魔改。固然,我無比感恩這些開發者的貢獻,但我以爲咱們應該被 Android 官方善待。
而後是 data flow。對於 UI 編程來講,分發事件和接收狀態是與開發者關聯最密切的事情。而現有的 android.widget 在這兩個方面都作得不夠好:狀態的管理比較混亂;事件在分發時就已經改變了控件的狀態;listener 能夠跟 Kotlin 結合更緊密提供更合適的作法。
聲明式編程一般是相對於命令式編程(imperative programming)來講的,不關注編程中具體的過程,而是以最後的結果爲重點。在 UI 這一特定的領域來講,聲明式編程則意味着:當狀態發生變化時,聲明式框架會自動更新視圖。
聲明式的 UI 框架會關注:
也就是說,它只關心當前的數據(狀態)會渲染出什麼樣的外觀,而不把數據當成一個擁有上下文的狀態流來看待。
Composition over inheritance.
組合優於繼承。
Compose 經過組合的方式構成界面。這或許也是起名叫 Compose 的緣由。
遵循單一責任原則,Compose 函數都只有一個單一的目的,想實現某一種效果,就使用對應的 Compose 函數。好比想要設置背景,則須要使用 Surface
,沒有其餘 Compose 函數能夠作到這一點。
使用 @Composable
註解的函數只能在另外一個的 Composable 函數中調用。看到這句話,你可能會想起:「 只有替身才能打倒替身 !」
若是你對 Kotlin Coroutine 有所瞭解,suspend 函數也一樣只能在 suspend 函數中進行調用。而 coroutine 的實現,是 Kotlin 編譯器在編譯時,將 suspend 函數進行了改造,會給函數添加一個 Continuation 參數,並對函數體進行必定程度的改造。詳細的這裏很少寫了。
對於 Composable 函數,一樣也是使用了 Kotlin 編譯器插件將函數變形了。Composable 函數裏添加的則是 Composer,這是一個相似於 gap buffer 的數據結構。Gap buffer 在文本編輯器裏被廣泛使用,有興趣的能夠多瞭解一下。
再次強調,Compose 處於很早期的階段,API 也好,具體的底層實現也好,都極可能會發生變化。官方的示例 JetNews 也存在必定的性能問題。
因此我以爲普通開發者還不須要去了解具體使用的細節。但仍是有幾個建議:
Codelab - Jetpack Compose Basics
Declarative UI Patterns (Google I/O'19)