欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Jetpack?Compose狀態(tài)專篇精講

 更新時(shí)間:2022年10月26日 10:51:05   作者:唯鹿  
在今年的Google/IO大會(huì)上,亮相了一個(gè)全新的?Android?原生?UI?開發(fā)框架-Jetpack?Compose,?與蘋果的SwiftIUI一樣,Jetpack?Compose是一個(gè)聲明式的UI框架,這篇文章主要介紹了Jetpack?Compose狀態(tài)管理

應(yīng)用中的狀態(tài)是指可以隨時(shí)間變化的任何值。這是一個(gè)非常寬泛的定義,從 Room 數(shù)據(jù)庫到類的變量,全部涵蓋在內(nèi)。

由于Compose是聲明式UI,會(huì)根據(jù)狀態(tài)變化來更新UI,因此狀態(tài)的處理至關(guān)重要。這里的狀態(tài)你可以簡單理解為頁面上展示的數(shù)據(jù),那么狀態(tài)管理就是處理數(shù)據(jù)的讀寫。

1.remember

remember就是用來保存狀態(tài)的,下面舉一個(gè)小例子。

@Composable
fun HelloContent() {
   Column(modifier = Modifier.padding(16.dp)) {
       OutlinedTextField(
           value = "",
           onValueChange = { },
           label = { Text("Name") }
       )
   }
}

比如我們在頁面中加了一個(gè)輸入框,如果只是上面代碼中這樣處理,那你會(huì)發(fā)現(xiàn)我們輸入的文字不會(huì)被記錄起來,輸入框中始終都是空的。這是因?yàn)閷傩?code>value被固定成了空字符串。我們使用remember優(yōu)化一下:

@Composable
fun HelloContent() {
    val inputValue = remember { mutableStateOf("") }
    Column(modifier = Modifier.padding(16.dp)) {
        OutlinedTextField(
            value = inputValue.value,
            onValueChange = {
                inputValue.value = it
            },
            label = { Text("Name") }
        )
    }
}

通過onValueChange更新value,mutableStateOf 會(huì)創(chuàng)建可觀察的 MutableState<T>,value 變更時(shí),系統(tǒng)會(huì)重組讀取 value 的所有Composable函數(shù),這樣就會(huì)自動(dòng)更新UI。

Jetpack Compose 并不強(qiáng)制要求你使用 MutableState 存儲(chǔ)狀態(tài)。Jetpack Compose 支持其他可觀察類型。在 Jetpack Compose 中讀取其他可觀察類型之前,您必須將其轉(zhuǎn)換為 State,以便 Jetpack Compose 可以在狀態(tài)發(fā)生變化時(shí)自動(dòng)重組界面。

  • LiveData中可以使用擴(kuò)展函數(shù) observeAsState()轉(zhuǎn)換為 State。
  • Flow 中可以使用擴(kuò)展函數(shù) collectAsState()轉(zhuǎn)換為 State。
  • RxJava中可以使用擴(kuò)展函數(shù)subscribeAsState()轉(zhuǎn)換為 State。

2.rememberSaveable

雖然 remember 可幫助您在重組后保持狀態(tài),但不會(huì)幫助您在配置更改后保持狀態(tài)。為此,您必須使用 rememberSaveablerememberSaveable 會(huì)自動(dòng)保存可保存在 Bundle 中的任何值。

還是上面的例子,如果我們旋轉(zhuǎn)屏幕,就會(huì)發(fā)現(xiàn)輸入框中的文字會(huì)丟失。此時(shí)就可以使用rememberSaveable 替換remember 來幫助我們恢復(fù)界面狀態(tài)。

由于保存的數(shù)據(jù)都是在 Bundle 中的,因此可保存的數(shù)據(jù)類型是有限制的。比如基礎(chǔ)類型、String、Parcelable,Serializable等。一般來說需要保存的對象加個(gè) @Parcelize 注解就可以解決問題。

如果某種原因?qū)е聼o法使用 @Parcelize ,你可以使用 mapSaver 自定義規(guī)則,定義如何將對象保存和恢復(fù)到 Bundle。

data class City(val name: String, val country: String)
val CitySaver = run {
    val nameKey = "Name"
    val countryKey = "Country"
    mapSaver(
        save = { mapOf(nameKey to it.name, countryKey to it.country) },
        restore = { City(it[nameKey] as String, it[countryKey] as String) }
    )
}
@Composable
fun CityScreen() {
    var selectedCity = rememberSaveable(stateSaver = CitySaver) {
        mutableStateOf(City("Madrid", "Spain"))
    }
}

如果你覺得定義map的key麻煩,可以使用 listSaver 并將其索引用作鍵。

data class City(val name: String, val country: String)
val CitySaver = listSaver<City, Any>(
    save = { listOf(it.name, it.country) },
    restore = { City(it[0] as String, it[1] as String) }
)
@Composable
fun CityScreen() {
    var selectedCity = rememberSaveable(stateSaver = CitySaver) {
        mutableStateOf(City("Madrid", "Spain"))
    }
}

3.狀態(tài)提升

對于上面使用到rememberrememberSaveState 方法來保存狀態(tài)的Composable函數(shù),我們稱為有狀態(tài)。有狀態(tài)的好處是調(diào)用方不需要控制狀態(tài),并且不必自行管理狀態(tài)。但是,具有內(nèi)部狀態(tài)的Composable往往不易重復(fù)使用,也更難測試。

在開發(fā)可重復(fù)使用的Composable時(shí),您通常想要同時(shí)提供同一Composable的有狀態(tài)和無狀態(tài)版本。有狀態(tài)版本對于不關(guān)心狀態(tài)的調(diào)用方來說很方便,而無狀態(tài)版本對于需要控制或提升狀態(tài)的調(diào)用方來說是必要的。

Compose 中的狀態(tài)提升是一種將狀態(tài)移至調(diào)用方以使可組合項(xiàng)無狀態(tài)的模式。

舉例說明一下狀態(tài)提升,比如我們實(shí)現(xiàn)一個(gè)Dialog,為了方便使用我們可以將里面顯示的文字,點(diǎn)擊事件邏輯寫到dialog的內(nèi)部封裝起來,雖然使用簡單但不具有通用性。那么為了通用,我們可以將文字,點(diǎn)擊事件的回調(diào)當(dāng)參數(shù)傳入,這樣就靈活了起來。

狀態(tài)提升其實(shí)就是這樣一個(gè)編程思想,只是換了個(gè)名詞,沒有什么特別了。

對于上面輸入框的例子,我們用狀態(tài)提示優(yōu)化一下:

@Composable
fun HelloScreen() {
    var name by rememberSaveable { mutableStateOf("") }
    HelloContent(name = name, onNameChange = { name = it })
}
@Composable
fun HelloContent(name: String, onNameChange: (String) -> Unit) {
    Column(modifier = Modifier.padding(16.dp)) {
        OutlinedTextField(
            value = name,
            onValueChange = onNameChange,
            label = { Text("Name") }
        )
    }
}

這樣就實(shí)現(xiàn)了Composable函數(shù)HelloContent 與狀態(tài)的存儲(chǔ)方式解耦,便于我們復(fù)用。

狀態(tài)下降、事件上升的這種模式稱為“單向數(shù)據(jù)流”。在這種情況下,狀態(tài)會(huì)從 HelloScreen 下降為 HelloContent,事件會(huì)從 HelloContent 上升為 HelloScreen。通過遵循單向數(shù)據(jù)流,您可以將在界面中顯示狀態(tài)的可組合項(xiàng)與應(yīng)用中存儲(chǔ)和更改狀態(tài)的部分解耦。

4.狀態(tài)管理

根據(jù)可組合項(xiàng)的復(fù)雜性,需要考慮不同的備選方案:

將Composable作為可信來源

用于管理簡單的界面元素狀態(tài)。比如上一篇提到的LazyColumn滾動(dòng)到指定item,將交互都放在當(dāng)前的Composable中進(jìn)行。

	val listState = rememberLazyListState()
    val coroutineScope = rememberCoroutineScope()
    LazyColumn(
        state = listState,
    ) {
       /* ... */
    }
	Button(
        onClick = {
            coroutineScope.launch {
                listState.animateScrollToItem(index = 0)
            }
        }
    ) {
        ...
    }

其實(shí)查看rememberLazyListState的源碼,可以看到實(shí)現(xiàn)很簡單:

@Composable
fun rememberLazyListState(
    initialFirstVisibleItemIndex: Int = 0,
    initialFirstVisibleItemScrollOffset: Int = 0
): LazyListState {
    return rememberSaveable(saver = LazyListState.Saver) {
        LazyListState(
            initialFirstVisibleItemIndex,
            initialFirstVisibleItemScrollOffset
        )
    }
}

將狀態(tài)容器作為可信來源

當(dāng)可組合項(xiàng)包含涉及多個(gè)界面元素狀態(tài)的復(fù)雜界面邏輯時(shí),應(yīng)將相應(yīng)事務(wù)委派給狀態(tài)容器。這樣做更易于單獨(dú)對該邏輯進(jìn)行測試,還降低了可組合項(xiàng)的復(fù)雜性。該方法支持分離關(guān)注點(diǎn)原則:可組合項(xiàng)負(fù)責(zé)發(fā)出界面元素,而狀態(tài)容器包含界面邏輯和界面元素的狀態(tài)。

@Composable
fun MyApp() {
    MyTheme {
        val myAppState = rememberMyAppState()
        Scaffold(
            scaffoldState = myAppState.scaffoldState,
            bottomBar = {
                if (myAppState.shouldShowBottomBar) {
                    BottomBar(
                        tabs = myAppState.bottomBarTabs,
                        navigateToRoute = {
                            myAppState.navigateToBottomBarRoute(it)
                        }
                    )
                }
            }
        ) {
            NavHost(navController = myAppState.navController, "initial") { /* ... */ }
        }
    }
}

rememberMyAppState代碼:

class MyAppState(
    val scaffoldState: ScaffoldState,
    val navController: NavHostController,
    private val resources: Resources,
    /* ... */
) {
    val bottomBarTabs = /* State */

    val shouldShowBottomBar: Boolean
        get() = /* ... */

    fun navigateToBottomBarRoute(route: String) { /* ... */ }

    fun showSnackbar(message: String) { /* ... */ }
}
@Composable
fun rememberMyAppState(
    scaffoldState: ScaffoldState = rememberScaffoldState(),
    navController: NavHostController = rememberNavController(),
    resources: Resources = LocalContext.current.resources,
    /* ... */
) = remember(scaffoldState, navController, resources, /* ... */) {
    MyAppState(scaffoldState, navController, resources, /* ... */)
}

其實(shí)就是再封裝一層,用戶處理邏輯。封裝的部分就叫狀態(tài)容器,用于管理Composable的邏輯和狀態(tài)。

將 ViewModel 作為可信來源

一種特殊的狀態(tài)容器類型,用于提供對業(yè)務(wù)邏輯以及屏幕或界面狀態(tài)的訪問權(quán)限。

ViewModel 的生命周期比Composable長,因此不應(yīng)保留對綁定到組合生命周期的狀態(tài)的長期引用。否則,可能會(huì)導(dǎo)致內(nèi)存泄漏。建議屏幕級Composable使用 ViewModel 來提供對業(yè)務(wù)邏輯的訪問權(quán)限并作為其界面狀態(tài)的可信來源。如需了解 ViewModel 為何適用于這種情況,請參閱 ViewModel 和狀態(tài)容器部分。

本篇到此結(jié)束,幫忙點(diǎn)個(gè)贊~ 給我一點(diǎn)鼓勵(lì),你也可以收藏本篇以備不時(shí)之需。

參考

狀態(tài)和 Jetpack Compose

到此這篇關(guān)于Jetpack Compose狀態(tài)專篇精講的文章就介紹到這了,更多相關(guān)Jetpack Compose狀態(tài)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Android仿網(wǎng)易新聞圖片詳情下滑隱藏效果示例代碼

    Android仿網(wǎng)易新聞圖片詳情下滑隱藏效果示例代碼

    這篇文章主要給大家介紹了關(guān)于利用Android如何仿網(wǎng)易新聞圖片詳情下滑隱藏效果的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-07-07
  • Android TextWatcher內(nèi)容監(jiān)聽死循環(huán)案例詳解

    Android TextWatcher內(nèi)容監(jiān)聽死循環(huán)案例詳解

    這篇文章主要介紹了Android TextWatcher內(nèi)容監(jiān)聽死循環(huán)案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • Android自定義View實(shí)現(xiàn)可拖拽縮放的矩形框

    Android自定義View實(shí)現(xiàn)可拖拽縮放的矩形框

    這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)可拖拽縮放的矩形框,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-05-05
  • Android View事件分發(fā)和消費(fèi)源碼簡單理解

    Android View事件分發(fā)和消費(fèi)源碼簡單理解

    這篇文章主要介紹了Android View事件分發(fā)和消費(fèi)源碼簡單理解的相關(guān)資料,需要的朋友可以參考下
    2017-07-07
  • Android仿微信進(jìn)度彈出框的實(shí)現(xiàn)方法

    Android仿微信進(jìn)度彈出框的實(shí)現(xiàn)方法

    最近公司項(xiàng)目需要實(shí)現(xiàn)類似微信進(jìn)度條彈出框效果,其實(shí)現(xiàn)方法并不難,下面給大家介紹下Android仿微信進(jìn)度彈出框的實(shí)現(xiàn)方法,需要的朋友參考下吧
    2017-01-01
  • Android實(shí)現(xiàn)花瓣飄落效果的步驟

    Android實(shí)現(xiàn)花瓣飄落效果的步驟

    這篇文章主要介紹了Android實(shí)現(xiàn)花瓣飄落效果的步驟,幫助大家更好的理解和學(xué)習(xí)使用Android開發(fā),感興趣的朋友可以了解下
    2021-04-04
  • Android學(xué)習(xí)筆記(二)之電話撥號(hào)器

    Android學(xué)習(xí)筆記(二)之電話撥號(hào)器

    目前手機(jī)市場上android已經(jīng)具有強(qiáng)大的霸主地位,吸引了很多的追棒者,android學(xué)習(xí)越來越火熱,本文給大家介紹android學(xué)習(xí)筆記(二)之電話撥號(hào)器,感興趣的朋友一起學(xué)習(xí)吧
    2015-11-11
  • Android捕捉錯(cuò)誤try catch 的簡單使用教程

    Android捕捉錯(cuò)誤try catch 的簡單使用教程

    這篇文章主要介紹了Android捕捉錯(cuò)誤try catch 的簡單使用,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-09-09
  • Android開發(fā)之天氣趨勢折線圖

    Android開發(fā)之天氣趨勢折線圖

    在開發(fā)天氣APP的時(shí)候會(huì)要顯示多天的信息,所以加一個(gè)折線圖來顯示一下天氣變化趨勢是很不錯(cuò)的效果,本文詳細(xì)介紹了開發(fā)過程,下面一起來看看。
    2016-08-08
  • Android無限循環(huán)RecyclerView的完美實(shí)現(xiàn)方案

    Android無限循環(huán)RecyclerView的完美實(shí)現(xiàn)方案

    這篇文章主要介紹了Android無限循環(huán)RecyclerView的完美實(shí)現(xiàn)方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06

最新評論