Android ViewModel中如何将insertUser返回的id传递给insertMoney函数
问题原因
- 异步执行时序问题:
insertUser内部通过uiScope.launch启动了异步协程任务,数据库插入逻辑是在IO线程执行的耗时操作。你在Fragment中调用insertUser后立刻执行insertMoney,此时insertUser的数据库插入操作还未完成,全局变量idT还没被赋值,因此拿到的是空字符串。 - 全局变量设计缺陷:用全局变量
idT存储单次操作的临时id本身就不合理,多并发场景下极易出现脏读、值被覆盖的问题,完全不适合该场景的参数传递需求。
解决方案
最直接的优化方式是调整函数结构,将insertUser改为可返回插入id的挂起函数,在调用侧按顺序执行两个操作,完全不需要额外定义全局变量存储中间值:
第一步 修改ViewModel代码
// 删掉原有全局变量idT class AddUserViewModel( val mUserInfoDAO: UserDAO, val mTransactionDAO: TransactionsDAO, val mLoan: LoanDAO, val mBankDAO: BankDAO, application: Application ) : AndroidViewModel(application) { var viewModelJob = Job() val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob) // 改为挂起函数,执行完成直接返回插入的用户id suspend fun insertUser( fullName: String, accountId: String, mobileNumber: String, phoneNumber: String, dateOfCreation: String, address: String, ): Long = withContext(Dispatchers.IO) { return@withContext try { Log.d("TAG", "insertTest") val user = UserInfo( 0L, fullName, accountId, mobileNumber, phoneNumber, dateOfCreation, address ) val id = mUserInfoDAO.insert(user) Log.d("TAG", "insertUser: $id") id } catch (e: Exception) { Log.d("TAG", "insertContact: ${e.message}") -1L // 异常场景返回无效id供调用侧判断 } } // 新增userId参数接收插入的用户id fun insertMoney( amount: String, increasePage: String?, userId: Long ) { Log.d("TAG", "insertUserTTT: $userId") val bankId: Long = bankInfo.value?.get(selectedItemPosition)?.bankId!! uiScope.launch { mTransactionDAO.insert( Transaction( 0L, userId, // 直接使用传入的id null, bankId, null, amount, null, null, null, increasePage ) ) } } // 新增onCleared逻辑防止内存泄漏 override fun onCleared() { super.onCleared() viewModelJob.cancel() } }
第二步 修改Fragment调用逻辑
mAddUserViewModel.addUser.observe(viewLifecycleOwner, Observer { if (it == true) { // 启动生命周期协程按顺序执行操作 lifecycleScope.launch { val userId = mAddUserViewModel.insertUser( mAddUserListBinding.fullName.text.toString(), mAddUserListBinding.accountId.text.toString(), mAddUserListBinding.mobileNumber.text.toString(), mAddUserListBinding.phoneNumber.text.toString(), mAddUserListBinding.createdDate.text.toString(), mAddUserListBinding.edtAddress.text.toString(), ) // 仅插入用户成功后再执行插入金额逻辑 if (userId != -1L) { val firstMoney = "firstMoney" mAddUserViewModel.insertMoney( mAddUserListBinding.firstMoney.text.toString(), firstMoney, userId ) } findNavController().popBackStack() } } })
内容的提问来源于stack exchange,提问作者AmirHossein
相关产品推荐
相关产品推荐

