色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

在Compose中使用狀態(State)

谷歌開發者 ? 來源:Android 開發者 ? 作者:Android ? 2022-04-21 11:05 ? 次閱讀
對于開發者來說,狀態 (State) 指應用中可以隨時間變化的任何值。我們的應用天然便是擁有狀態的,無論您將數據存儲在本地還是服務器中,狀態都可以使這些數據更有價值。接下來,我們就以應用 Jetsnack 作為示例,談一談 Compose 中的狀態。aff35282-c114-11ec-bce3-dac502259ad0.png

Jetsnack 應用屏幕截圖

在 Compose 中使用 State

Jetsnack 是一款使用 Compose 構建的小吃訂購示例應用,狀態對它來說非常重要。比如,在一屏中顯示哪些商品、顯示用戶篩選的小吃以及記錄購物車等操作,都需要狀態的支持。我們將 Compose 構建的界面稱之為組合 (Composition),它會在屏幕中呈現應用的當前狀態。下圖直觀地展示了組合在視覺上呈現搜索頁的過程,您可以在其中找到搜索欄 (SearchBar)、分隔線 (JetsnackDivider) 和搜索建議 (SearchSuggestions),這些都是搜索界面的組成部分:

b0141404-c114-11ec-bce3-dac502259ad0.png

△組合呈現搜索界面的過程

在像 Compose 這樣的聲明式框架中,您只需描述應用的當前狀態,Compose 會負責在狀態發生更改時更新界面。因此,當我們導航到購物車屏幕時,Compose 也會重新執行受狀態更改影響的部分界面。下圖中,NavHost 更新為顯示購物車界面。由于界面的每個部分都是一個可組合項,當狀態更改時,這些函數會進行重組,以便在屏幕上顯示新數據:

b02b3d1e-c114-11ec-bce3-dac502259ad0.png

△組合呈現購物車界面的過程

在購物車界面中,我們重點關注單獨的購物車商品項。該元素用于顯示購物車中的商品,并允許您更改數量:

b03e3a4a-c114-11ec-bce3-dac502259ad0.gif

△單獨的購物車商品

我們可以使用包含兩個 Button 和一個 Text 的 Row 來構建該界面,但是要如何記錄購物車中商品的當前數量呢?

@Composablefun CartItem() {    var quantity = ... ˉ\_(ッ)_/ˉ ... ?     Row {        Button(onClick = { quantity++ }) {            Text("+")        }        Text(quantity.toString())        Button(onClick = { quantity-- }) {            Text("-")        }    }}
我們可以簡單地在可組合函數中添加一個可變變量 quantity,但接下來您會發現,在我們通過點按增加和減少數量的按鈕來修改此變量的值時,界面中顯示的數量沒有發生任何變化——當狀態更改時,該函數沒有重新組合。這是因為 Compose 不會跟蹤 quantity 變量。
@Composablefun CartItem() {    var quantity: Int = 1    ...}
b281b07a-c114-11ec-bce3-dac502259ad0.gif△數量的顯示沒有發生改變

Compose 具有特殊的狀態跟蹤系統,可以在某個狀態改變時,重組讀取該狀態的所有可組合項。這種機制使得 Compose 可以對界面進行精細控制,在狀態發生改變時不用修改整個界面,只需重組需要更改的可組合函數即可。

這一功能是通過跟蹤狀態寫入 (即狀態更改) 以及狀態讀取來實現的,我們可以使用 Compose 的 State 和 MutableState 類型使狀態可被觀察。Compose 會跟蹤讀取 State 中 value 屬性的可組合項,并在 value 發生更改時觸發重新組合。

// Stateinterface State<out T> {    val value: T} // MutableStateinterface MutableState<T> : State<T> {    override var value: T}

您可以使用 mutableStateOf 函數創建 MutableState,該函數需要接收一個初始值,并且它的 value 是可變的。相應的,我們需要改用 value 屬性來讀取和寫入 quantity 狀態:

@Composablefun CartItem() {    val quantity: MutableState<Int> = mutableStateOf(1)     Row {        Button(onClick = { quantity.value++ }) {            Text("+")        }        Text(quantity.value.toString())        Button(onClick = { quantity.value-- }) {            Text("-")        }    }}

但是,即使 Compose 已經跟蹤了 quantity 變量,并觸發了重組,您會發現界面依然沒有顯示狀態的更改。問題在于,雖然該函數已經重組,但 quantity 的值 value 總是會被初始化為 1。這是一個常見的錯誤,因此您在嘗試編寫這段代碼時也會產生編譯錯誤。為了在重組中重用 quantity 狀態,我們需要使其成為組合的一部分。要做到這一點,可以使用 remember 可組合函數將對象存儲在組合中:

@Composablefun CartItem() {    val quantity = remember { mutableStateOf(1) }    ...}

Remember 可用于存儲可變對象和不可變對象,您必須對在組合中創建的 State,也就是可組合函數中的 State 執行 remember 操作。在被記住后,狀態將成為組合的一部分,并在函數重組時被重用,這樣一來,購物車商品也可以按照我們的預期工作了。

由于重新組合期間會保留 quantity,因此屏幕上將顯示改變后的新值。此外,Compose 還提供了 rememberSaveable,其行為與 remember 類似,但存儲的值可在 Activity 和進程重建后保留下來,這是在配置變更時保留界面數據的好方法。rememberSaveable 適用于界面狀態,如商品數量或選定的標簽,但不適用諸如過渡動畫狀態一類的用例。

此外,您還可以將委托屬性與 State API 結合使用。在下面的代碼中可以看到,在實際應用中,我們可以使用 by 關鍵字來實現這一點。如果您不想每次都訪問 value 屬性的話,這不失為一種好方法。

@Composablefun CartItem() {    var quantity: Int by rememberSaveable { mutableStateOf(1) }     Row {        Button(onClick = { quantity++ }) {            Text("+")        }        Text(quantity.toString())        Button(onClick = { quantity-- }) {            Text("-")        }    }}

注意,您只應在可組合函數的作用域之外操作狀態,因為可組合項可能會頻繁地、以任何順序執行。上面的代碼中,在 onClick 監聽器中修改 quantity 的操作是安全的,因為 onClick 不是可組合函數。您可以根據特定的用戶輸入觸發狀態更改,例如點擊按鈕或使用附帶效應:

https://developer.android.google.cn/jetpack/compose/side-effects

狀態提升

Compose 相比起 View 系統的一大優勢,便是更為良好的可復用性。然而在當前的形式下,您無法復用 CartItem 可組合函數,因為它總是會將私有的 quantity 初始化為 1。在真實的使用環境中,購物車中的商品并不總是都從 1 開始計數,而且用戶的購物車中也可能會有之前會話中的商品。與依賴注入的邏輯類似,為了使 CartItem 可重用,我們需要將 quantity 作為參數傳遞給該函數;不僅如此,為了遵循單一可信來源原則,傳遞給 CartItem 的 quantity 應該不可變。 單一可信來源原則鼓勵結構化的代碼,以便只在一個位置修改數據。在本例中,如果 CartItem 不負責特定的狀態 (即 quantity),就不應該對它進行更新。因此 CartItem 需要在用戶與按鈕交互并觸發狀態更新時通知調用方。但是這樣一來,我們就需要考慮應該由誰負責更新 quantity 等狀態的操作。我們可以先假設 Cart 可組合項應該擁有所有 CartItem 的信息,以及相應地更新這些信息的邏輯:b3595f84-c114-11ec-bce3-dac502259ad0.png△ 假設 Cart 可組合項負責更新每個購物車的商品數量

為了使 CartItem 可被重用,我們將 quantity 狀態從 CartItem 提升至 Cart 中,這一過程被稱為狀態提升:

https://developer.android.google.cn/jetpack/compose/state

狀態提升是一種將私有狀態移出可組合項的模式,這可以使可組合項更趨于無狀態,從而提高在應用中的可重用性。無狀態可組合項是指不保存任何私有狀態的可組合項。理想情況下,可組合項應接收狀態作為參數,并使用 lambda 向上傳遞事件:

b36cddfc-c114-11ec-bce3-dac502259ad0.png

△可組合項應接收狀態 (State)

并使用 lambda 向上傳遞事件 (Events)

使可組合項趨于無狀態,不但可以使其符合單一可信來源原則,而且可以提高它的可重用性和可測試性。因為在這種情況下,可組合項沒有與任何特定的數據處理方式耦合在一起,而我們還可以共享和攔截以這種方式提升的狀態。下面是無狀態版的 CartItem 的示例代碼,它接收 quantity 并做為狀態顯示,同時將用戶交互公開為事件:

@Composablefun CartItem(    quantity: Int, // 狀態    incrementQuantity: () -> Unit, // 事件    decrementQuantity: () -> Unit // 事件) {    Row {        Button(onClick = incrementQuantity) {            Text("+")        }        Text(quantity.toString())        Button(onClick = decrementQuantity) {            Text("-")        }    }}

接下來我們來看 Cart 可組合函數的實現。Cart 界面會在 LazyColumn 中顯示不同的 CartItem,同時負責使用正確的信息調用 CartItem。Cart 中的項目實際上是從 CartViewModel 取得的應用數據。我們對于每個 CartItem 都傳入特定的 quantity,增加或減少數量的邏輯被委托給 ViewModel,ViewModel 則作為 Cart 數據的持有者:

@Composablefun Cart(viewModel: CartViewModel = viewModel()) {     val cartItems by viewModel.cartItems     LazyColumn {        items(cartItems) { item ->            CartItem(                quantity = item.quantity,                incrementQuantity = {                    viewModel.inrementQuantity(item)                },                decrementQuantity = {                    viewModel.decrementQuantity(item)                }            )        }    }}

狀態提升是一種在 Compose 中廣泛使用的模式。作為一種攔截和控制界面元素內部使用狀態的方式,您可以在大多數 Compose API 中看到它。我們也可以將攔截狀態設計為可選操作,從而可以利用強大的默認參數特性。以下面的代碼為例,如果需要控制或共享 scaffoldState,您可以傳入該狀態;而如果您沒有傳入,該函數也會創建一個默認狀態:

@Composablefun Scaffold(    scaffoldState: ScaffoldState = rememberScaffoldState(),    ...) { ... } @Composablepublic fun NavHost(        navController: NavHostController,        ...){...}

在上面的例子中,我們只是假設應該由 Cart 可組合函數負責 CartItem 的狀態更新。那么在我們實際去應用時,應該將狀態提升到多高的層級呢?這其實是一個數據所有權的問題,如果您不能確定,則至少應將狀態提升到需要訪問該狀態的所有可組合項的最低公共父級。在本例中,CartItem 的最低公共父級是 Cart,也就是負責使用正確的信息調用 CartItem 的層級。狀態提升另一個原則是,可組合項應該只接受所需的參數。在 Jetsnack 中,我們使用了無狀態的 Cart 可組合項,它只接受需要的參數:
@Composablefun Cart(    orderLines: List<OrderLine>,    removeSnack: (Long) -> Unit,    increaseItemCount: (Long) -> Unit,    decreaseItemCount: (Long) -> Unit,    inspiredByCart: SnackCollection,    modifier: Modifier = Modifier) {    ...}

這樣的 Cart 可組合項更易于預覽和測試,同時符合單一可信來源原則。這樣做的可重用性也更高,比如,如果我們需要,就可以在窗口尺寸足夠大的情況下,與另一個界面并排顯示購物車。不僅如此,我們還提供了有狀態版本,使其也可以通過特定的方式處理狀態和事件:

@Composablefun Cart(    modifier: Modifier = Modifier,    viewModel: CartViewMo = viewModel()) {    val orderLines by viewModel.orderLines.collectAsState()     Cart(        orderLines = orderLines,        removeSnack = viewModel::removeSnack,        increaseItemCount = viewModel::increaseSnackCount,        decreaseItemCount = viewModel::decreaseSnackCount,        inspiredByCart = viewModel.inspiredByCart,        modifier = modifier    )}

我們可以看到,這個版本的 Cart 通過處理業務邏輯和狀態的 CartViewModel 來調用無狀態版的 Cart 可組合項。這種同時提供有狀態、無狀態,或趨于無狀態組合項的模式,可以很好的兼顧各種使用場景。您既可以在需要時重用可組合項,又可以在應用中以特定的方式使用它。

狀態管理

狀態應至少提升到最低公共父級,但是否應該總是將狀態置于可組合項中?在前面的例子中我們可以看到,Jetsnack Cart 使用的是與 Compose Navigation 集成度很好的 ViewModel。在下面的表格中,列出了幾種管理和定義可信來源的方式,以及它們所對應的狀態類型,在下面的文章中將對它們進行詳細的介紹:

b3884736-c114-11ec-bce3-dac502259ad0.png

注意: 如果對應用例不能應用 ViewModel 的優勢,那么就可以用一般的狀態持有者代替 ViewModel

在開始之前,我們要定義文中所涉及特定術語的含義:

  • 界面元素狀態: 是指被提升的界面元素狀態。例如,ScaffoldState。
  • 屏幕或界面的狀態:是指需要在屏幕上顯示的內容。例如,CartUiState 可以包含購物車商品、向用戶顯示的消息或加載標記。此類狀態通常會與層次結構中的其他層級相關聯,因為其包含應用數據。
  • 界面的行為邏輯:與如何在界面上顯示狀態更改相關。例如,導航邏輯或顯示信息提示控件。界面行為邏輯應始終位于組合中。
  • 業務邏輯:決定如何處理狀態更改。比如,進行支付或存儲用戶偏好設置。這類邏輯通常應置于業務層或數據層,絕不應置于界面層。
在大致了解了這些概念后,讓我們來看看處理狀態的不同方式。首先,如果您要處理的界面元素狀態比較簡單,就可以放在可組合項中。在本例中,JetsnackApp 可組合項中持有 scaffoldState。由于 scaffoldState 包含可變屬性,因此,與之相關的所有交互都應在該可組合項中進行。如果將 scaffoldState 傳遞給其他可組合項,這些可組合項可能會改變其狀態。這不符合單一可信來源原則,而且會使對錯誤的跟蹤變得更加困難。
@Composablefun JetsnackApp() {    JetsnackTheme {        val scaffoldState = rememberScaffoldState()        val coroutineScope = rememberCoroutineScope()         JetsnackScaffold(scaffoldState = scaffoldState) {            Content(                    showSnackbar = { message ->                        coroutineScope.launch {                            scaffoldState.snackbarHostState                                    .showSnackbar(message)                        }                    }            )        }    }}
但是,實際情況往往更加復雜。JetsnackApp 除了會發送界面元素外,還負責顯示信息提示控件、導航到正確的屏幕、設置底部操作欄等操作。將所有這些內容都放在可組合項中,會使它難以閱讀和理解。我們可以遵循分離關注點原則,將屏幕邏輯和界面元素狀態委托給名為 "狀態容器"的類,從而讓可組合函數只負責生成界面元素。 一般類型作為狀態容器

我們使用 JetsnackAppState 類作為狀態容器,它將會是 JetsnackApp 的界面元素狀態的可信來源,因此所有狀態寫入都應在該類中進行。狀態容器是在組合中創建和記住的普通類,因此,該類的作用域限定于創建它的可組合項。JetsnackAppState 只是一個普通類,而且由于它遵循可組合項的生命周期,因此可以使用 Compose 的依賴項,而不必擔心內存泄漏:

class JetsnackAppState(    // 一般的類可以接收 Compose 依賴    val scaffoldState: ScaffoldState,    val navController: NavHostController,    ...) {    val shouldShowBottomBar: Boolean        // 在讀取的值發生改變時會進行重組        @Composable get() = navController.currentBackStackEntryAsState().value            ?.destination?.route in bottomBarRoutes     // 與界面相關的邏輯    fun navigateToBottomBarRoute(route: String) {        if (route != currentRoute) {            navController.navigate(route) {                launchSingleTop = true                restoreState = true                popUpTo(findStartDestination(navController.graph).id) {                    saveState = true                }            }        }    }}

狀態容器還可以包含可組合項屬性,更改此類屬性將會觸發重組,上面的代碼即為是否顯示底部操作欄的屬性。該狀態容器還包含界面相關的邏輯,比如導航邏輯。就像前面說過的,您必須使用 remember 記住數據,以便在重新組合期間重用數據,如果狀態容器使用了 State 依賴項,那么應該提供方法來記住狀態容器。在下面的代碼中,我們將依賴項傳入 remember,以便在任何依賴項發生更改時獲取 JetsnackAppState 的新實例:

@Composablefun rememberJetsnackAppState(    scaffoldState: ScaffoldState = rememberScaffoldState(),    navController: NavHostController = rememberNavController(),    ...) = remember(scaffoldState, navController, ...) {    JetsnackAppState(scaffoldState, navController, ...)}

現在,我們在 JetsnackApp 中獲取了 appState 的新實例。我們使用該實例將被提升的狀態傳遞給可組合項,并在需要顯示界面元素時檢查該狀態;同時調用函數來觸發與界面相關的操作:

@Composablefun JetsnackApp() {    JetsnackTheme {        val appState = rememberJetsnackAppState()        JetsnackScaffold(            scaffoldState = appState.scaffoldState,            bottomBar = {                if (appState.shouldShowBottomBar) {                    JetsnackBottomBar(                        tabs = appState.bottomBarTabs,                        navigateToRoute = {                            appState.navigateToBottomBarRoute(it)                        }                    )                }            }        ) {NavHost(navController=appState.navController,...){

簡單來說,狀態容器是一個普通類,用于提升界面元素的狀態并包含界面相關的邏輯。狀態容器可以降低可組合項的復雜性,并提高其可測試性,從而有助于關注點分離。它還可以使狀態提升變得更為容易,因為只需提升一個狀態而不是多個狀態。狀態容器可以非常簡單并且只用于特定用途,例如,只用于搜索界面的 SearchState 類,其中僅包含 activeFilters 和 searchResults List。當您需要跟蹤狀態或界面邏輯時可以使用狀態容器來幫助控制復雜度。

class SearchState {    var searchResults: List by mutableStateOf(listOf())        private set     var activeFilters: List by mutableStateOf(listOf())        private set     ...}
ViewModel 作為狀態容器

除了一般的狀態容器外,我們還可以使用 ViewModel,這是一種繼承架構組件 ViewModel 類的類。ViewModel 可用作由業務邏輯確定狀態的狀態容器。ViewModel 有兩項責任: 首先,提供對應用業務邏輯的訪問,這些業務邏輯通常位于層次結構的其他層級中,如存儲區或用例中;其次,準備要在特定屏幕上呈現的應用數據,通常是用可觀察類型呈現屏幕的界面狀態。

在完全使用 Compose 構建的應用中,我們可以使用 Compose 的 State 類型。但在混合應用中,您還可能會用到其他的可觀察類型,如 StateFlow:

class CartViewModel(    private val repository: SnackRepository,    private val savedState: SavedStateHandle) : ViewModel() {     val uiState: State = ...     fun increaseSnackCount(snackId: Long) { ... }    fun decreaseSnackCount(snackId: Long) { ... }    fun removeSnack(snackId: Long) { ... }    fun completeOrder() { ... }}

ViewModel 在配置變更后仍然有效,因此其生命周期比組合更長。ViewModel 不屬于組合的一部分,因此不能接受組合作用域內的狀態,比如使用記住的值,您需要謹慎對待此類操作,因為這可能會導致內存泄漏。ViewModel 依賴于層次結構的其他層級,例如存儲區或用例。另外,如果您希望界面在狀態發生更改時重組,您依然需要使用 Compose State API。

class CartViewModel(    private val repository: SnackRepository,    private val savedState: SavedStateHandle) : ViewModel() {     // 在 ViewModel 中,仍要使用 State 類型來使狀態可被 Compose 觀察    var uiState by mutableStateOf(EmptyCart)         private set        ...}

不過在本例中,由于 uiState 位于組合之外,因此您不需要記住它,而只需使用它即可。可組合函數將在 uiState 更改時重新執行:

@Composablefun Cart(viewModel: CartViewModel = viewModel()) {    val uiState by viewModel.uiState}

層次結構的其他層通常使用流式數據來傳播更改,您可能已經開始在 ViewModel 中使用它們了。Flow 也可以很好地與 Compose 結合使用,我們提供了工具函數,可以將數據流轉換為 Compose 的可觀察 State API。例如,您可以使用 collectAsState 從數據流中收集值,并將它們呈現為 State。這樣一來,每當數據流發出新值時,就會觸發重組。

@Composablefun Cart(viewModel: CartViewModel = viewModel()) {    // 通過將 Flow 轉換為 State 來跟蹤 snacks 狀態的改變    val snacks by viewModel.snacks.collectAsState()    ...}

總的來說,ViewModel 可以在組合之外提升組合的狀態,同時具有更長的生命周期。ViewModel 負責屏幕的業務邏輯并決定要顯示哪些數據,它會從其他層級獲取數據,并準備這些要呈現的數據。因此,建議在屏幕級的可組合項中使用 ViewModel。

與普通狀態容器相比 ViewModel 具有一些優勢,其中包括,ViewModel 觸發的操作在配置變更后仍然有效,并且 ViewModel 可以與 Hilt、Navigation 等 Jetpack 庫很好地集成在一起。在使用 Hilt 時,僅使用一行代碼,就能通過 Hilt 提供的依賴項獲取 ViewModel。

當屏幕位于返回棧中時,Navigation 會緩存 ViewModel,這意味著當返回到目標時,數據已經處于可用狀態;而當目標離開返回棧后 ViewModel 又會被清除,從而確保狀態可以被自動清理。

使用遵循可組合項界面生命周期的狀態容器 (即使用一般的類作為狀態容器),將會難以做到前述操作。盡管如此,如果 ViewModel 的優勢不適用于您的用例或者您以不同的方式操作,您可以使用其他最適合您的狀態容器,而不一定是 ViewModel 來完成相應的工作。

同時使用 ViewModel 和其他狀態容器

界面級可組合項也可以同時使用 ViewModel 和其他狀態容器。由于 ViewModel 的生命周期更長,普通的狀態容器可以將 ViewModel 作為依賴項。

我們來看一下實際應用。除了在 Cart 可組合項中使用 CartViewModel 之外,我們還可以另外使用包含界面元素狀態和界面邏輯的 CartState。在 CartState 中,我們使用 lazyListState 來記錄大型購物車界面的滾動位置;使用 resources 來格式化信息和價格;如果允許展開商品以顯示更多信息,還可以了解每個商品的狀態:

class CartState(    lazyListState: LazyListState,    resources: Resources,    expandedItems: List = emptyList()) {    ...    fun formatPrice(...) { ... }}

Cart 中同時使用了 ViewModel 和其他狀態容器,它們具有不同的用途,并可以協同工作。我們來仔細看一下它們的生命周期: CartState 會遵循 Cart 可組合項的生命周期,當 Cart 從組合中移除后 CartState 也會一同移除;而 CartViewModel 具有不同的生命周期,即導航目的地、導航圖、Fragment 或 Activity 的生命周期:

b39ca6b8-c114-11ec-bce3-dac502259ad0.png

CartState 遵循 Cart 的生命周期

而 CartViewModel 則位于組合之外

從全局來看,每個實體的作用都有明確的定義,從包含界面元素的界面層到包含業務邏輯的數據層,每個實體都有特定的用途。在下圖中,您可以看到扮演著不同角色的實體,以及它們之間潛在的依賴關系:

b3b52de6-c114-11ec-bce3-dac502259ad0.png實體間的關系及它們對應的用途

總結

對于我們的應用來說,狀態是十分重要的一部分。我們可以在 Compose 中使用 State API 做到簡單的狀態響應,也可以使用一般的類或者 ViewModel 作為狀態容器,以便對可組合項進行狀態提升,并使其符合單一可信來源原則。我們還可以組合不同的狀態容器,從而利用它們各自不同的生命周期。

下面是我們在文章中列出的表格,請記住它,以便您在未來做決策時可以為您的應用提供明確的狀態管理架構:

b3884736-c114-11ec-bce3-dac502259ad0.png希望現在您能更加理解這個表格的意義

希望本文能幫助您實現 "理想的 Compose 狀態",祝您擁有愉快的 Compose 使用體驗。

原文標題:實踐 | Jetpack Compose 中的狀態管理

文章出處:【微信公眾號:谷歌開發者】歡迎添加關注!文章轉載請注明出處。

審核編輯:湯梓紅
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 狀態
    +關注

    關注

    0

    文章

    16

    瀏覽量

    11956
  • State
    +關注

    關注

    0

    文章

    5

    瀏覽量

    7672
  • 開發者
    +關注

    關注

    1

    文章

    577

    瀏覽量

    17026

原文標題:實踐 | Jetpack Compose 中的狀態管理

文章出處:【微信號:Google_Developers,微信公眾號:谷歌開發者】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    關于狀態中使用事件情況的問題

    如圖1,2.問題是,我現在想要實現第二種情況,如圖流程(situation 2), state 1判斷信號input是否等于3,如果等于3,進入狀態3,如果5秒內沒有信號發生,或信號不等于3,就進入
    發表于 05-16 19:22

    Coke Machine State Machine

    `Coke Machine State Machine 源碼:、官方給的例程中加以修改,關于狀態機是個很好的學習范例。PDF資料截圖如下:`
    發表于 08-06 19:42

    QT中使用按鍵事件檢測按鍵狀態

    嵌入式Linux系統中,用QT做的應用層程序,需要檢測自定義的按鍵狀態。使用的QT的按鍵事件,驅動層使用的Linux的input子系統。環境如下:硬件:Imx6ullQT版本:5.5QT中使用按鍵
    發表于 10-27 10:31

    compose的使用技巧是什么?

    compose的使用技巧是什么?
    發表于 11-15 07:27

    LCA(邏輯單元陣列)器件中使狀態

    State-machine methodology defines the contents of everyflip-flop in a design under every
    發表于 05-15 13:21 ?10次下載

    State Machine Coding Styles for Synthesis

    本文論述了狀態機的verilog編碼風格,以及不同編碼風格的優缺點, Steve Golsons 1994 paper, State Machine Design Techniques
    發表于 01-17 11:22 ?0次下載
    <b class='flag-5'>State</b> Machine Coding Styles for Synthesis

    如何使用 Compose 進行構建

    適用于 Wear OS 的 Compose 已推出了開發者預覽版,使用 Compose 構建 Wear OS 應用,不僅可以輕松遵循 Material You 指南,同時可以將 Compose 的優點發揮出來。
    的頭像 發表于 03-17 13:44 ?1780次閱讀

    Jetpack Compose基礎知識科普

    Jetpack Compose 是用于構建原生 Android 界面的新工具包。它可簡化并加快 Android 上的界面開發,使用更少的代碼、強大的工具和直觀的 Kotlin API,快速讓應用生動
    的頭像 發表于 04-02 13:38 ?2980次閱讀

    Docker Compose Docker應用構建管理工具

    ./oschina_soft/compose.zip
    發表于 05-12 15:58 ?1次下載
    Docker <b class='flag-5'>Compose</b> Docker應用構建管理工具

    Compose社區中的反響

    我們很高興地看到這些團隊大規模和復雜的生產環境中仔細地評估并使用了 Compose,所帶來的結果也不僅是讓界面開發更清晰有趣,也帶來了更多工程上的收益。這只是其中幾個案例,因為 Play 商店排名前 1,000 的應用中有超過 100 個正在使用
    的頭像 發表于 05-18 10:15 ?1056次閱讀

    Compose Material 3 穩定版現已發布 | 2022 Android 開發者峰會

    (新一代 Material Design ) 構建 Jetpack Compose 界面。立即開始應用中使用 Material Design 3 吧! Compose Materi
    的頭像 發表于 11-21 18:10 ?1195次閱讀

    Jetpack Compose 更新一覽 | 2022 Android 開發者峰會

    作者 /?Android 開發者關系工程師 Jolanda Verhoef 去年我們發布了 Jetpack Compose ,此后一直進行優化。我們已添加了新的功能并創造出功能更強大的工具,幫助
    的頭像 發表于 11-23 17:55 ?1132次閱讀

    Kotlin聲明式UI框架Compose Multiplatform支持iOS

    JetBrains ?KotlinConf’23 大會上宣布,Compose Multiplatform 已支持 iOS,目前處于 alpha 階段。至此,Compose
    的頭像 發表于 04-24 09:12 ?1314次閱讀
    Kotlin聲明式UI框架<b class='flag-5'>Compose</b> Multiplatform支持iOS

    PiSquare中使用PiHut狀態

    電子發燒友網站提供《PiSquare中使用PiHut狀態板.zip》資料免費下載
    發表于 06-13 15:38 ?0次下載
    <b class='flag-5'>在</b>PiSquare<b class='flag-5'>中使</b>用PiHut<b class='flag-5'>狀態</b>板

    docker-compose配置文件內容詳解以及常用命令介紹

    。 使用 docker-compose.yml 定義構成應用程序的服務,這樣它們可以隔離環境中一起運行。 最后,執行 docker-compose up 命令來啟動并運行整個應用程序。 二、docker-
    的頭像 發表于 12-02 09:29 ?527次閱讀
    docker-<b class='flag-5'>compose</b>配置文件內容詳解以及常用命令介紹
    主站蜘蛛池模板: 玩弄人妻少妇500系列网址 | 一个人在线观看免费中文www| 久久黄色大片| jlzz中国jizz日本老师水多| 亚洲精品123区| 日操夜操天天操| 兰桂坊人成社区亚洲精品| 国产精品免费一区二区区| ASIAN大陆明星裸休合成PICS| 一本道本线中文无码| 天天看高清影视在线18| 欧美最猛12teevideos| 乐乐亚洲精品综合影院| 精品午夜视频| 国产日韩成人内射视频| 成人在线免费视频| 99久久国产综合精品国| 诱人的秘书BD在线观看| 亚洲精品久久午夜麻豆| 乌克兰成人性色生活片| 日韩精品 中文字幕 有码| 免费中文字幕视频| 老师你下面好紧夹死了| 九九热精品视频在线观看| 国产午夜精品视频在线播放| 国产成人啪精视频精东传媒网站| WWWXXXX兽交| poronovideos动物狗猪| 99久久久久精品国产免费麻豆| 中文字幕亚洲无限码| 孕妇泬出白浆18P| 亚洲在线视频自拍精品| 亚洲精品无码午夜福利在线观看| 性色香蕉AV久久久天天网| 无人区乱码区1卡2卡三卡在线| 肉欲横流(NP高H)| 色戒未删减版在线观看完整| 日本熟妇多毛XXXXX视频| 日本888xxxx| 色老板美国在线观看| 十分钟免费看完整视频|