kotlin 在Android Studio中使用Jetpack Compose和Room Database创建支持登录的笔记应用时,如何检索正确的用户ID?

oknrviil  于 2023-05-23  发布在  Kotlin
关注(0)|答案(2)|浏览(229)

无法获取正确的用户ID,无法为登录用户分配备注。

嘿,在过去的两周里,我一直在努力解决一个问题,同时使用Jetpack Compose和Room Database在Android Studio中创建一个支持登录的笔记应用程序。我刚开始学习,这个问题让我抓狂,因为我知道有经验的人可能会在5分钟内解决这个问题。
首先,我想提一下,我在论坛text上发现了一个类似的问题,但提供的解决方案在我的情况下不起作用,我甚至试图向ChatGPT寻求帮助,但仍然不起作用。
下面,我将提供LoginRegisterViewModel、NotesViewModel和CreateNoteComposable函数的代码,我将在其中调用登录用户。对不起,代码混乱,但这是我的代码的“最后版本”,当我试图修复这个:/
登录注册视图模型:

class LoginRegisterViewModel(app: Application) : AndroidViewModel(app) {

    private val repo = UserRepository(app.applicationContext)
    private var userExist = false
    private val currentUser = MutableStateFlow<User?>(null)

    private var userId : Int? = null

    suspend fun checkPassword(username: String, password: String): Boolean {
        return withContext(Dispatchers.IO) {
            val user = getUserByLoginAndPassword(username, password)
            user != null
        }
    }

    fun getUserId(): Int? {
        println(userId)
        return userId
    }

    private fun setCurrentUser(user: User) {
        currentUser.value = user
        userId = user.id
    }

    suspend fun checkIfUserExists(loginValue: String): Boolean {
        return withContext(Dispatchers.IO) {
            val user = repo.getUserByLogin(loginValue)
            user != null
        }
    }
    private suspend fun getUserByLoginAndPassword(
        loginValue: String,
        passwordValue: String
    ): User? {
        return repo.getUserByLoginAndPassword(loginValue, passwordValue)
    }

    suspend fun login(loginValue: String, passwordValue: String): Boolean {
        return withContext(Dispatchers.IO) {
            val user = getUserByLoginAndPassword(loginValue, passwordValue)
            if (user != null) {
                setCurrentUser(user)
                userId = repo.getUserId(loginValue)
                println(currentUser.value)
                true
            } else {
                false
            }
        }
    }

    fun logout() {
        currentUser.value = null
    }

    fun registerUser(
        nameValue: String,
        loginValue: String,
        passwordValue: String,
        confirmPasswordValue: String
    ) {
        viewModelScope.launch(Dispatchers.IO) {
            if (passwordValue == confirmPasswordValue) {
                userExist = false
                val user = User(
                    nameValue = nameValue,
                    loginValue = loginValue,
                    passwordValue = passwordValue
                )
                repo.insert(user)
            } else {
                userExist = true
            }
        }
    }
}

NotesViewModel:

class NotesViewModel(
    private val repo: NotesRepository, private val userId: Int?
) : ViewModel() {

    val getNotesByUserId: List<Note> = runBlocking { repo.getNotesByUserId(userId) }

    fun deleteNotes(note: Note) {
        viewModelScope.launch(Dispatchers.IO) {
            repo.deleteNote(note)
        }
    }

    fun updateNote(note: Note) {
        viewModelScope.launch(Dispatchers.IO) {
            repo.updateNote(note)
        }
    }

    fun createNote(title: String, note: String, userId: Int?) {
        viewModelScope.launch(Dispatchers.IO) {
            repo.insertNote(Note(title = title, note = note, userId = userId))
            println(userId)
        }
    }

    suspend fun getNote(noteId: Int): Note? {
        return repo.getNoteById(noteId)
    }

}

@Suppress("UNCHECKED_CAST")
class NotesViewModelFactory(
    private val repo: NotesRepository, private val loginRegisterViewModel: LoginRegisterViewModel
) : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        return NotesViewModel(repo, loginRegisterViewModel.getUserId()) as T
    }
}

CreateNote可组合函数:

@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter", "UnusedMaterialScaffoldPaddingParameter")
@Composable
fun CreateNote(
    navController: NavController,
    viewModel: NotesViewModel,
    userId: Int?
) {
    val currentNote = remember {
        mutableStateOf("")
    }

    val currentTitle = remember {
        mutableStateOf("")
    }

    val saveButtonState = remember {
        mutableStateOf(false)
    }

    val currentUser = remember {
        mutableStateOf(userId)
    }

    println(currentUser)

    NotepadTheme {
        Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
            Scaffold(
                topBar = {
                    AppBar(
                        title = "Create Note",
                        onIconClick = {

                            viewModel.createNote(
                                currentTitle.value,
                                currentNote.value,
                                currentUser.value
                            )
                            navController.popBackStack()
                        },
                        icon = {
                            Icon(
                                imageVector = ImageVector.vectorResource(R.drawable.save),
                                contentDescription = stringResource(R.string.save_note),
                                tint = Color.Black,
                            )
                        },
                        iconState = remember { mutableStateOf(true) }
                    )
                },
            ) {
                Column(
                    Modifier
                        .padding(12.dp)
                        .fillMaxSize()
                ) {

                    TextField(
                        value = currentTitle.value,
                        modifier = Modifier.fillMaxWidth(),
                        onValueChange = { value ->
                            currentTitle.value = value
                            saveButtonState.value =
                                currentTitle.value != "" && currentNote.value != ""
                        },
                        colors = TextFieldDefaults.textFieldColors(
                            cursorColor = Color.Black,
                            focusedLabelColor = Color.Black
                        ),
                        label = { Text(text = "Title") }
                    )
                    Spacer(modifier = Modifier.padding(12.dp))

                    TextField(
                        value = currentNote.value,
                        modifier = Modifier
                            .fillMaxHeight(0.5f)
                            .fillMaxWidth(),
                        onValueChange = { value ->
                            currentNote.value = value
                            saveButtonState.value =
                                currentTitle.value != "" && currentNote.value != ""
                        },
                        colors = TextFieldDefaults.textFieldColors(
                            cursorColor = Color.Black,
                            focusedLabelColor = Color.Black
                        ),
                        label = { Text(text = "Note") }
                    )
                }

            }
        }
    }
}

提前感谢任何形式的帮助!

gfttwv5a

gfttwv5a1#

我已经找到了一种将userId传递到NotesList页面的方法。首先,删除我在第一个答案中所说的所有更改,并从NotesViewModel类中删除用户对象参数。
我在你的代码中看到,在LoginRegisterViewModel中,你有currentUser的流对象,它从数据库中检索当前用户对象,我测试了它,以了解它是否正确地获取值,所以你不需要任何额外的方法来获取userId。

composable("notelist_page/{userId}",
                    arguments = listOf(navArgument("userId"){
                        type = NavType.IntType
                    })
                ) {
                    val userId = remember {
                        it.arguments?.getInt("userId")
                    }
                    if(userId != null){
                        NoteList(navController = navController,notesViewModel,userId)
                    }

                }

在NotesList组合中添加userId参数并像我一样更改路由,以便在路由参数中将userId从登录页面发送到NotesList页面。
在登录页面中,您将如何导航

// Sprawdź, czy hasło zostało uzupełnione i czy zgadza się z użytkownikiem
            if (passwordState.value.isNotEmpty() && validPassword) {
                         // Wywołaj funkcję logowania z ViewModel
                             runBlocking {
                                loginRegisterViewModel.login(
                                        loginState.value,
                                        passwordState.value
                                    )
                                }
          navController.navigate(
"notelist_page/${loginRegisterViewModel.currentUser.value!!.id}"
) {
      launchSingleTop = true
      }
}

最后在NotesListPage中修改NotesViewModel中userId的值

fun NoteList(
    navController: NavController,
    viewModel: NotesViewModel,
    userId : Int
) {

    viewModel.userId.value = userId
    val notes = viewModel.getNotesByUserId

}

NotesViewModel中的这些代码行将使用userId检索notes列表。

class NotesViewModel(
    private val repo: NotesRepository, private val userRepo: UserRepository
) : ViewModel() {

    var userId = mutableStateOf(0)

    val getNotesByUserId: List<Note> = runBlocking { 
                 repo.getNotesByUserId(userId.value) 
}

在做了所有这些更改之后,出现了一个关于userId生成的错误,所以它所做的就是从Entity类中删除Unique key参数并保持简单,autoGenerate = true属性足以生成新的id。

@Entity(tableName = Constants.USERS_TABLE_NAME)
data class User(
    @PrimaryKey(autoGenerate = true) val id: Int? = 0,
    @ColumnInfo(name = "nameValue") val nameValue: String,
    @ColumnInfo(name = "loginValue") val loginValue: String,
    @ColumnInfo(name = "passwordValue") val passwordValue: String
)

完成此更改后,您还必须更改RoomDatabase版本并设置迁移,如果您不想提及迁移,只需添加.fallbackToDestructiveMigration()。

private var db: AppDatabase? = null

        fun getInstance(context: Context): AppDatabase {
            if (db == null) {
                db = Room.databaseBuilder(context, AppDatabase::class.java, Constants.DATABASE_NAME)
                //    .addMigrations(MIGRATION_2_3)
                    .fallbackToDestructiveMigration()
                    .build()
            }
            return db!!
        }
lnxxn5zx

lnxxn5zx2#

在你的dao类中,你可以这样做,通过传入用户名来获取用户id。

@Query("SELECT userId FROM User WHERE username = :username")
    suspend fun getUserIdByUsername(username: String): Int?

然后将此函数添加到存储库中,然后在NotesViewModel中创建一个mutableStateOf Int,并将userId传递到notesViewModel的构造函数中,而不是传递整个user对象

class NotesViewModel(
    private val repo: NotesRepository, private val user: User?
) : ViewModel()

#and then create a mutableStateOf Int and initialize it to zero in the NotesViewModel,

var userId = mutableStateOf(0)

#create a init block in the NotesViewModel and call the function from the #repository

init {
   userId = repo.getUserIdByUsername(user.username)
}

最后,在可组合中,您可以执行以下操作:从参数中删除userId

var userId by remember{
   mutableStateOf(viewModel.userId.value)
}

LaunchedEffect(viewModel.userId.value){
userId = viewModel.userId.value
}

你应该通过这种方式获取TheUser id,你可以在进一步的函数中使用它:)

相关问题