Jetpack Compose+;androidx.compose.runtime.SlotTableKt.groupSize(SlotTable.kt:2558)上的Firebase崩溃java.lang.ArrayIndexOutOfBoundsException
我正在使用firbase firestore实时数据库开发一个应用程序。 一旦用户首次登录,应用程序将检查用户是否有用户名。如果没有,它将显示一个弹出窗口,允许更改用户名。用户还可以通过抽屉菜单更改用户名,该菜单也将显示相同的弹出窗口 这是我的viewmodel的外观:Jetpack Compose+;androidx.compose.runtime.SlotTableKt.groupSize(SlotTable.kt:2558)上的Firebase崩溃java.lang.ArrayIndexOutOfBoundsException,android,firebase,kotlin,google-cloud-firestore,android-jetpack-compose,Android,Firebase,Kotlin,Google Cloud Firestore,Android Jetpack Compose,我正在使用firbase firestore实时数据库开发一个应用程序。 一旦用户首次登录,应用程序将检查用户是否有用户名。如果没有,它将显示一个弹出窗口,允许更改用户名。用户还可以通过抽屉菜单更改用户名,该菜单也将显示相同的弹出窗口 这是我的viewmodel的外观: class MainViewModel : ViewModel() { private val _user = FirebaseAuth.getInstance().currentUser private val
class MainViewModel : ViewModel() {
private val _user = FirebaseAuth.getInstance().currentUser
private val _isLoggedIn = MutableLiveData(FirebaseAuth.getInstance().currentUser != null)
val profile = UserProfile(_user.uid)
var isLoaded: LiveData<Boolean> = profile.isLoaded
var isLoggedIn: LiveData<Boolean> = _isLoggedIn
init {
getInstance().addAuthStateListener() {
_isLoggedIn.value = it.currentUser != null
}
}
fun updateUsername(username: String) {
profile.updateUsername(username)
}
fun logOut(){
FirebaseAuth.getInstance().signOut()
}
}
最后,我的change用户名组合如下所示:
class UserProfile(private val userId: String) {
private val _isLoaded = MutableLiveData(false)
private val _username = MutableLiveData("")
var isLoaded: LiveData<Boolean> = _isLoaded
var username: LiveData<String> = _username
init {
if (userId != "") {
Firebase.firestore.collection("Users").document(userId)
.addSnapshotListener { snapshot, e ->
if (e != null)
return@addSnapshotListener
if (snapshot != null) {
if (snapshot.exists()) {
snapshot.getString("username")?.let { setUsername(it) }
if (_isLoaded.value == false)
_isLoaded.value = true
} else {
val data = hashMapOf("username" to "")
FirebaseFirestore.getInstance().collection("Users").document("")
.set(data)
}
}
}
}
}
private fun setUsername(newUsername: String) {
_username.value = newUsername
}
fun updateUsername(newUsername: String) {
if (userId != "") {
val data = hashMapOf("username" to newUsername)
FirebaseFirestore.getInstance().collection("Users").document(userId)
.set(data, SetOptions.merge())
}
}
}
fun Main(mainViewmodel: MainViewModel = viewModel(), navHostController: NavHostController) {
var fabShape = CircleShape
val state = rememberScaffoldState()
val scope = rememberCoroutineScope()
val isLoggedIn: Boolean by mainViewmodel.isLoggedIn.observeAsState(true)
val isLoaded: Boolean by mainViewmodel.isLoaded.observeAsState(false)
val username: String by mainViewmodel.profile.username.observeAsState("")
var showUsernameChange: Boolean by remember (username){ mutableStateOf(false)}
if (!isLoggedIn)
navHostController.navigate(Screen.Login.route)
Scaffold(
scaffoldState = state,
topBar = {
TopAppBar(
title = { Text(text = "AppName") },
navigationIcon = {
IconButton(onClick = {
if (state.drawerState.isClosed) scope.launch { state.drawerState.open() }
else scope.launch { state.drawerState.close() }
}) {
Icon(Icons.Filled.AccountCircle, null)
}
}
)
},
bottomBar = {
BottomAppBar(cutoutShape = fabShape) {
BottomNavigationItem(
selected = true,
onClick = { /*TODO*/ },
icon = { Icon(Icons.Filled.Home, null) })
BottomNavigationItem(
selected = false,
onClick = { /*TODO*/ },
icon = { Icon(Icons.Filled.Favorite, null) })
BottomNavigationItem(
selected = false,
onClick = { /*TODO*/ },
icon = { Icon(Icons.Filled.Search, null) })
BottomNavigationItem(
selected = false,
onClick = { /*TODO*/ },
icon = { Icon(Icons.Filled.Settings, null) })
}
},
drawerShape = RoundedCornerShape(
topStart = 10.dp,
topEnd = 10.dp,
bottomStart = 10.dp,
bottomEnd = 10.dp,
),
drawerContent = {
Drawer(username = username, onLogoutClick = {mainViewmodel.logOut()}, onUsernameChangeClick = {
showUsernameChange = true
scope.launch { state.drawerState.close() }
})
},
drawerGesturesEnabled = true,
isFloatingActionButtonDocked = true,
floatingActionButtonPosition = FabPosition.Center,
floatingActionButton = {
FloatingActionButton(
onClick = { /*TODO*/ },
shape = fabShape,
content = { Icon(Icons.Filled.Add, null) })
}
) {
if (isLoaded) {
content(mainViewmodel = mainViewmodel)
val hasUsername: Boolean by remember(username) { mutableStateOf(username.isNotEmpty())}
if (!hasUsername || showUsernameChange) {
var cacheUsername: String by remember { mutableStateOf(username) }
changeUsername(
cacheUsername,
onNameChange = { cacheUsername = it },
onDismiss = {if(showUsernameChange){
showUsernameChange = false
} },
onDoneClick = {
mainViewmodel.updateUsername(cacheUsername)
})
}
} else {
loading()
}
}
}
fun changeUsername(username: String, onNameChange : (String) -> Unit, onDoneClick : () -> Unit, onDismiss: () -> Unit){
val error : Boolean = username.isNullOrEmpty() || username.length > 64 || username.length < 4
Dialog(onDismissRequest = { onDismiss() }) {
Card() {
Column(modifier = Modifier.padding(4.dp)) {
Text(text = "Update Username", modifier = Modifier.padding(4.dp), style = MaterialTheme.typography.subtitle2)
TextField(value = username,
onValueChange = { onNameChange(it) },
modifier = Modifier.padding(4.dp),
isError = error,
placeholder = { Text("Username") })
TextButton(
onClick = { onDoneClick() }, modifier = Modifier
.padding(4.dp)
.align(Alignment.End),
enabled = !error
) {
Text("Done")
}
}
}
}
}
这是怎么回事?我们如何修复它?看起来像这样。看起来修复程序已经实现,有望在Beta 2中发布!你认为它与对话有关吗?是的,这就是它的样子。确认。删除对话框,工作正常。您认为我应该将此报告为一个问题吗?还有一个问题的代码与您的()类似,但它被标记为与我之前链接的问题重复。鉴于stacktrace完全相同,因此值得验证该问题是否在最新的Compose快照上得到了解决。您可以按照androidx.dev上的说明将其包括在内。如果这不能解决您的问题,请提交另一个问题。
java.lang.ArrayIndexOutOfBoundsException: length=5120; index=-2
at androidx.compose.runtime.SlotTableKt.groupSize(SlotTable.kt:2558)
at androidx.compose.runtime.SlotTableKt.access$groupSize(SlotTable.kt:1)
at androidx.compose.runtime.SlotReader.groupSize(SlotTable.kt:596)
at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2215)
at androidx.compose.runtime.ComposerImpl.skipCurrentGroup(Composer.kt:2499)
at androidx.compose.runtime.ComposerImpl.recompose$runtime_release(Composer.kt:2625)
at androidx.compose.runtime.CompositionImpl.recompose(Composition.kt:406)
at androidx.compose.runtime.Recomposer.performRecompose(Recomposer.kt:724)
at androidx.compose.runtime.Recomposer.access$performRecompose(Recomposer.kt:100)
at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:437)
at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:411)
at androidx.compose.ui.platform.AndroidUiFrameClock$withFrameNanos$2$callback$1.doFrame(AndroidUiFrameClock.android.kt:34)
at androidx.compose.ui.platform.AndroidUiDispatcher.performFrameDispatch(AndroidUiDispatcher.android.kt:112)
at androidx.compose.ui.platform.AndroidUiDispatcher.access$performFrameDispatch(AndroidUiDispatcher.android.kt:43)
at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.doFrame(AndroidUiDispatcher.android.kt:72)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:964)
at android.view.Choreographer.doCallbacks(Choreographer.java:790)
at android.view.Choreographer.doFrame(Choreographer.java:721)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:951)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)