亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

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

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

1.remember

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

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

比如我們在頁面中加了一個輸入框,如果只是上面代碼中這樣處理,那你會發(fā)現我們輸入的文字不會被記錄起來,輸入框中始終都是空的。這是因為屬性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 會創(chuàng)建可觀察的 MutableState<T>,value 變更時,系統(tǒng)會重組讀取 value 的所有Composable函數,這樣就會自動更新UI。

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

  • LiveData中可以使用擴展函數 observeAsState()轉換為 State。
  • Flow 中可以使用擴展函數 collectAsState()轉換為 State。
  • RxJava中可以使用擴展函數subscribeAsState()轉換為 State。

2.rememberSaveable

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

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

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

如果某種原因導致無法使用 @Parcelize ,你可以使用 mapSaver 自定義規(guī)則,定義如何將對象保存和恢復到 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函數,我們稱為有狀態(tài)。有狀態(tài)的好處是調用方不需要控制狀態(tài),并且不必自行管理狀態(tài)。但是,具有內部狀態(tài)的Composable往往不易重復使用,也更難測試。

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

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

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

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

對于上面輸入框的例子,我們用狀態(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") }
        )
    }
}

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

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

4.狀態(tài)管理

根據可組合項的復雜性,需要考慮不同的備選方案:

將Composable作為可信來源

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

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

其實查看rememberLazyListState的源碼,可以看到實現很簡單:

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

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

當可組合項包含涉及多個界面元素狀態(tài)的復雜界面邏輯時,應將相應事務委派給狀態(tài)容器。這樣做更易于單獨對該邏輯進行測試,還降低了可組合項的復雜性。該方法支持分離關注點原則:可組合項負責發(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, /* ... */)
}

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

將 ViewModel 作為可信來源

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

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

本篇到此結束,幫忙點個贊~ 給我一點鼓勵,你也可以收藏本篇以備不時之需。

參考

狀態(tài)和 Jetpack Compose

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

相關文章

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

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

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

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

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

    Android自定義View實現可拖拽縮放的矩形框

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

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

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

    Android仿微信進度彈出框的實現方法

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

    Android實現花瓣飄落效果的步驟

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

    Android學習筆記(二)之電話撥號器

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

    Android捕捉錯誤try catch 的簡單使用教程

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

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

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

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

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

最新評論