问题描述
问题陈述 :当我按下注册按钮以注册新用户时,它会在来自实时数据的吐司中显示注册成功响应,但是当我尝试执行相同的按钮触发时,它会再次显示来自 API 的注册成功响应消息,然后还显示来自 API 的电话号码存在响应吐司。这也意味着实时数据返回旧响应。那么我该如何解决这个递归实时数据响应返回问题?
这里是问题视频链接以了解问题 在这里查看https://drive.google.com/file/d/1-hKGQh9k0EIYJcbInwjD5dB33LXV5GEn/view?usp=sharing
需要 ARGENT 帮助
我的 Api 界面
interface ApiServices {
/*
* USER LOGIN (GENERAL USER)
* */
@POST("authentication.php")
suspend fun loginUser(@Body requestBody: RequestBody): Response<BaseResponse>
}
我的存储库类
class AuthenticationRepository {
var apiServices: ApiServices = ApiClient.client!!.create(ApiServices::class.java)
suspend fun UserLogin(requestBody: RequestBody) = apiServices.loginUser(requestBody)
}
我的视图模型类
class RegistrationViewModel : BaseViewModel() {
val respository: AuthenticationRepository = AuthenticationRepository()
private val _registerResponse = MutableLiveData<BaseResponse>()
val registerResponse: LiveData<BaseResponse> get() = _registerResponse
/*
* USER REGISTRATION [GENERAL USER]
* */
internal fun performUserLogin(requestBody: RequestBody,onSuccess: () -> Unit) {
ioScope.launch {
isLoading.postValue(true)
tryCatch({
val response = respository.UserLogin(requestBody)
if (response.isSuccessful) {
mainScope.launch {
onSuccess.invoke()
isLoading.postValue(false)
_registerResponse.postValue(response.body())
}
} else {
isLoading.postValue(false)
}
},{
isLoading.postValue(false)
hasError.postValue(it)
})
}
}
}
我的注册活动
class RegistrationActivity : BaseActivity<ActivityRegistrationBinding>() {
override val layoutRes: Int
get() = R.layout.activity_registration
private val viewModel: RegistrationViewModel by viewModels()
override fun onCreated(savedInstance: Bundle?) {
toolbarController()
viewModel.isLoading.observe(this,{
if (it) showLoading(true) else showLoading(false)
})
viewModel.hasError.observe(this,{
showLoading(false)
showMessage(it.message.toString())
})
binding.registerbutton.setOnClickListener {
if (binding.registerCheckbox.isChecked) {
try {
val jsonObject = JSONObject()
jsonObject.put("type","user_signup")
jsonObject.put("user_name",binding.registerName.text.toString())
jsonObject.put("user_phone",binding.registerPhone.text.toString())
jsonObject.put("user_password",binding.registerPassword.text.toString())
val requestBody = jsonObject.toString()
.toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull())
viewModel.performUserLogin(requestBody) {
viewModel.registerResponse.observe(this){
showMessage(it.message.toString())
//return old reponse here then also new reponse multiple time
}
}
} catch (e: JSONException) {
e.printStackTrace()
}
} else {
showMessage("Please Accept Our Terms & Conditions")
}
}
}
override fun toolbarController() {
binding.backactiontoolbar.menutitletoolbar.text = "Registration"
binding.backactiontoolbar.menuicontoolbar.setOnClickListener { onBackPressed() }
}
override fun processIntentData(data: Uri) {}
}
解决方法
LiveData
是一个状态持有者,它并不是真的要用作事件流。然而,有许多关于该主题的文章(如 this one)描述了可能的解决方案,包括从 Google 示例中获取的 SingleLiveEvent 实现。
但截至目前,kotlin 协程库提供了更好的解决方案。特别是,channels 对于事件流非常有用,因为它们实现了 fan-out 行为,因此您可以有多个事件使用者,但每个事件只会被处理一次。 Channel.receiveAsFlow 可以非常方便地将流公开为流。否则,SharedFlow 是事件总线实现的一个很好的候选者。请注意 replay
和 extraBufferCapacity
参数。
您的 registerResponse 实时数据在按钮单击侦听器中观察,这就是它观察两次的原因!您的 registerResponse 实时数据应该观察按钮单击侦听器之外的数据 -
覆盖 fun onCreated(savedInstance: Bundle?) { 工具栏控制器()
viewModel.isLoading.observe(this,{
if (it) showLoading(true) else showLoading(false)
})
viewModel.registerResponse.observe(this){
showMessage(it.message.toString())
}
viewModel.hasError.observe(this,{
showLoading(false)
showMessage(it.message.toString())
})
binding.registerbutton.setOnClickListener {
if (binding.registerCheckbox.isChecked) {
try {
val jsonObject = JSONObject()
jsonObject.put("type","user_signup")
jsonObject.put("user_name",binding.registerName.text.toString())
jsonObject.put("user_phone",binding.registerPhone.text.toString())
jsonObject.put("user_password",binding.registerPassword.text.toString())
val requestBody = jsonObject.toString()
.toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull())
viewModel.performUserLogin(requestBody) {
}
} catch (e: JSONException) {
e.printStackTrace()
}
} else {
showMessage("Please Accept Our Terms & Conditions")
}
}
}