簡體   English   中英

Jetpack Compose 在方向改變時保存狀態

[英]Jetpack Compose saving state on orientation change

我正在使用 Android Jetpack 的 Compose,並且一直在嘗試弄清楚如何保存方向更改的狀態。

我的思路是讓一個類成為一個 ViewModel。 因為當我使用 Android 的傳統 API 時,這通常有效。

我已經使用 remember {} 和 mutableState {} 在信息發生更改時更新 UI。 請驗證我的理解是否正確...

記住 = 保存變量並允許通過 .value 訪問,這允許緩存值。 但它的主要用途是在更改時不重新分配變量。

mutableState = 在發生變化時更新變量。

許多博客文章都說要使用@Model,但是,在嘗試該方法時,導入會出錯。 所以,我添加了一個: ViewModel()

但是,我相信我記得 {} 阻止它按預期工作?

我能在正確的方向上得到一個點嗎?

@Composable
fun DefaultFlashCard() {

    val flashCards = remember { mutableStateOf(FlashCards())}
    

    Spacer(modifier = Modifier.height(30.dp))

    MaterialTheme {


        val typography = MaterialTheme.typography
        var question = remember { mutableStateOf(flashCards.value.currentFlashCards.question) }



        Column(modifier = Modifier.padding(30.dp).then(Modifier.fillMaxWidth())
                .then(Modifier.wrapContentSize(Alignment.Center))
                .clip(shape = RoundedCornerShape(16.dp))) {
            Box(modifier = Modifier.preferredSize(350.dp)
                    .border(width = 4.dp,
                            color = Gray,
                            shape = RoundedCornerShape(16.dp))
                    .clickable(
                            onClick = {
                                question.value = flashCards.value.currentFlashCards.answer })
                    .gravity(align = Alignment.CenterHorizontally),
                    shape = RoundedCornerShape(2.dp),
                    backgroundColor = DarkGray,
                    gravity = Alignment.Center) {
                Text("${question.value}",
                        style = typography.h4, textAlign = TextAlign.Center, color = White
                )
            }
        }

        Column(modifier = Modifier.padding(16.dp),
                horizontalGravity = Alignment.CenterHorizontally) {

            Text("Flash Card application",
                    style = typography.h6,
                    color = Black)

            Text("The following is a demonstration of using " +
                    "Android Compose to create a Flash Card",
                    style = typography.body2,
                    color = Black,
                    textAlign = TextAlign.Center)

            Spacer(modifier = Modifier.height(30.dp))
            Button(onClick = {
                flashCards.value.incrementQuestion();
                question.value = flashCards.value.currentFlashCards.question },
                    shape = RoundedCornerShape(10.dp),
                    content = { Text("Next Card") },
                    backgroundColor = Cyan)
        }
    }
}


data class Question(val question: String, val answer: String) {
}


class FlashCards: ViewModel() {

    var flashCards = mutableStateOf( listOf(
            Question("How many Bananas should go in a Smoothie?", "3 Bananas"),
            Question("How many Eggs does it take to make an Omellete?", "8 Eggs"),
            Question("How do you say Hello in Japenese?", "Konichiwa"),
            Question("What is Korea's currency?", "Won")
    ))

    var currentQuestion = 0

    val currentFlashCards
        get() = flashCards.value[currentQuestion]

    fun incrementQuestion() {
        if (currentQuestion + 1 >= flashCards.value.size) currentQuestion = 0 else currentQuestion++
    }
}

在 Compose 中有另一種處理配置更改的方法,它是rememberSaveable 正如文檔所說

雖然remember可以幫助您在重新組合時保留狀態,但狀態不會在配置更改時保留。 為此,您必須使用rememberSaveable rememberSaveable自動保存任何可以保存在 Bundle 中的值。 對於其他值,您可以傳入自定義保護程序對象。

似乎Mohammad 的解決方案更健壯,但這一個似乎更簡單。

和以前一樣,您可以使用架構組件 ViewModel 來應對配置更改。

您應該在 Activity/Fragment 中初始化您的 ViewModel,然后將其傳遞給 Composable 函數。

class UserDetailFragment : Fragment() {

    private val viewModel: UserDetailViewModel by viewModels()

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        return ComposeView(context = requireContext()).apply {
            setContent {
                AppTheme {
                    UserDetailScreen(
                        viewModel = viewModel
                    )
                }
            }
        }
    }
}

然后您的 ViewModel 應該通過 LiveData 或 Flow 之類的方式公開 ViewState

用戶詳細信息視圖模型:

class UserDetailViewModel : ViewModel() {
    private val _userData = MutableLiveData<UserDetailViewState>()
    val userData: LiveData<UserDetailViewState> = _userData


    // or

    private val _state = MutableStateFlow<UserDetailViewState>()
    val state: StateFlow<UserDetailViewState>
        get() = _state

}

現在您可以在可組合函數中觀察此狀態:

@Composable
fun UserDetailScreen(
    viewModel:UserDetailViewModel
) {
    val state by viewModel.userData.observeAsState()
    // or
    val viewState by viewModel.state.collectAsState()

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM