Pan*_*All 1 android kotlin android-viewmodel android-jetpack android-jetpack-compose
我正在使用 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++
}
}
Run Code Online (Sandbox Code Playgroud)
Moh*_*aki 15
Compose 中有 2 种内置的方法来保存状态:
remember:用于在重组之间保存可组合函数的状态。
rememberSaveable:remember 仅在重组过程中保存状态,不处理配置更改和进程死亡,因此为了在配置更改和进程死亡中幸存下来,您应该使用rememberSaveable它。
但也存在一些问题rememberSaveable:
它支持开箱即用的原始类型,但对于更复杂的数据,例如data class,您必须创建一个Saver来解释如何将状态保存到包中,
rememberSaveable在后台使用Bundle,因此可以保留的数据量是有限的,如果数据太大,您将面临TransactionTooLarge异常。
如上所述,可以使用以下解决方案:
设置以避免配置更改中的活动重新创建android:configChanges。Manifest(在进程死亡时没有用,也不能避免在 Android 12 中的壁纸更改中重新创建)
采用存储+数据持久化ViewModel的组合remeberSaveable
=================================================== =====
与以前一样,您可以使用架构组件 ViewModel 来应对配置更改。
您应该在 Activity/Fragment 中初始化 ViewModel,然后将其传递给可组合函数。
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
)
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后你的 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
}
Run Code Online (Sandbox Code Playgroud)
现在您可以在可组合函数中观察此状态:
@Composable
fun UserDetailScreen(
viewModel:UserDetailViewModel
) {
val state by viewModel.userData.observeAsState()
// or
val viewState by viewModel.state.collectAsState()
}
Run Code Online (Sandbox Code Playgroud)
小智 7
在 Compose 中有另一种处理配置更改的方法,它是rememberSaveable. 正如文档所说:
虽然
remember可以帮助您在重新组合时保留状态,但不会在配置更改时保留状态。为此,您必须使用rememberSaveable.rememberSaveable自动保存可以保存在 Bundle 中的任何值。对于其他值,您可以传入自定义保护程序对象。
似乎Mohammad 的解决方案更健壮,但这一个似乎更简单。
| 归档时间: |
|
| 查看次数: |
3861 次 |
| 最近记录: |