android - 如何从我的 POST 请求改造调用中获得对我的 Fragment 的响应
问题描述
我的目标是当我单击signUp-Button 并导航到verification-Fragment (如果 response.status 为 true时)从我的viewModel捕获或获取响应到我的signUp-Fragment中。
当我在我的 signUpFragment 中单击我的注册按钮时,会发出一个 POST 请求改造调用,并收到如下响应:
UserResponse(message=Sign up successful. A verfication code has been sent to your email address, payload=UserPayload(country=Nigeria, createdAt=2020-04-10T10:55:06.220Z, email=osehiproductengineer@gmail.com, id=5e90508a455f70002f19b42e, isVerified=false, name=osehiase ehilen, phone=07083372454, updatedAt=2020-04-10T10:55:06.220Z, v=0), status=200, token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI1ZTkwNTA4YTQ1NWY3MDAwMmYxOWI0MmUiLCJpYXQiOjE1ODY1MTYxMDYsImV4cCI6MTU4NjYwMjUwNn0.H_JhBQY-3PQ6Kqk7SS0cm8RP_1mzYlD987M66_LT0PU)
我使用 Log 看到了这个响应;响应没有到达我的 signUp-Fragment。
下面是我的存储库代码:
class NetworkRepository(): BaseRepository() {
val userApi = UserAPI()
val authAPI = AuthAPI()
val treeAPI = TreeAPI()
val paymentAPI = PaymentAPI()
val loginAPI = LoginAPI()
val TAG = "NETWORK REPOSITORY"
private val _networkState = MutableLiveData<NetworkState>()
val networkState: LiveData<NetworkState>
get() = _networkState
//User
suspend fun createUser(userBody: UserBody): UserResponse {
var status = UserResponse()
// Log.d("SIGNUP_RESPONSE2", "inside status:$status")
withContext(Dispatchers.IO){
try {
status = userApi.addUserAsync(userBody).await()
// Log.d("signup_Response3", "after the call:$status")
}catch (t: Throwable){
Log.e(TAG, t.message.toString())
}
}
Log.d("SIGNUP_RESPONSE", "here is the $status")
return status
}
}
这是我的视图模型代码:
class UserViewModel : ViewModel(){
private val repository = NetworkRepository()
private val job = Job()
private val scope = CoroutineScope(job + Dispatchers.Main)
fun createUser(userBody: UserBody):UserResponse {
var userPayload: UserResponse = UserResponse()
// Log.d("USERVIEWMODEL_TOP", "the first response:$userPayload")
scope.launch {
// userPayload = repository.createUser(userBody)
userPayload = repository.createUser(userBody)
// Log.d("USERVIEWMODELCHCK", "speak now:$userPayload")
}
// Log.d("USERVIEWMODEL_RESPONSE", "check this userViewModelRes:$userPayload")
return userPayload
}
}
这是我的注册片段代码:
class SignUpFragment : Fragment() {
private lateinit var viewModel: UserViewModel
private lateinit var userBody: UserBody
var captureStatus:UserResponse = UserResponse()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
viewModel = ViewModelProvider(this).get(UserViewModel::class.java)
return inflater.inflate(R.layout.fragment_sign_up, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
signup_submit_btn.setOnClickListener {
val response = sendUser()
// Log.d("SIGNUP_FRAGMENTRES", "where is this response:$response")
if (response.status == 200) {
Log.d("SIGNUP_FRAGMENT", "wat is here:${response}")
saveUserInfo(response)
findNavController().navigate(R.id.action_signUpFragment_to_verificationFragment)
} else {
Toast.makeText(
this.context,
"${response.status}, ${response.message}",
Toast.LENGTH_SHORT
).show()
}
}
signup_have_an_account.paintFlags = Paint.UNDERLINE_TEXT_FLAG
signup_have_an_account.setOnClickListener {
findNavController().navigate(R.id.action_signUpFragment_to_loginFragment)
}
signup_back_btn.setOnClickListener {
findNavController().popBackStack()
}
}
private fun sendUser(): UserResponse {
var userBody: UserBody? = null
//verification
when {
signup_email_input.editText!!.text.isEmpty() -> {
signup_email_input.editText!!.error = "Email cannot be empty"
}
signup_phone_input.editText!!.text.isEmpty() -> {
signup_phone_input.editText!!.error = "Phone cannot be empty"
}
signup_country_input.editText!!.text.isEmpty() -> {
signup_country_input.editText!!.error = "Country cannot be empty"
}
signup_password_input.editText!!.text.isEmpty() -> {
signup_password_input.editText!!.error = "Password cannot be empty"
}
signup_password_input.editText!!.text.length < 6 -> {
signup_password_input.editText!!.error = "Password cannot be less than 6 characters"
}
signup_name_input.editText!!.text.isEmpty() -> {
signup_name_input.editText!!.error = "Name cannot be empty"
}
else -> {
val email = signup_email_input.editText!!.text.toString()
val country = signup_country_input.editText!!.text.toString()
val name = signup_name_input.editText!!.text.toString()
val password = signup_password_input.editText!!.text.toString()
val phone = signup_phone_input.editText!!.text.toString()
userBody = UserBody(country, email, false, name, password, phone)
}
}
// Log.d("USER REG", userBody.toString())
return viewModel.createUser(userBody!!)
}
private fun saveUserInfo(userResponse: UserResponse) {
this.activity?.let { Preferences.setEmail(it, userResponse.payload!!.email) }
this.activity?.let { Preferences.saveAuthToken(it, userResponse.token!!) }
}
}
解决方案
用一些虚拟对象实例化变量(如:status
,userPayload
),然后用其他方法的响应更改它,然后通过return
函数返回它是不好的方法。您最好用 null 实例化它,并通过callback
. 然后,如果您现在立即使您为空,则出现问题。
上述方法是您问题的根源。因为该createUser
函数返回的是 DummyObject,而不是 Retrofit 的实际对象。要解决此问题,您需要从方法中删除return
函数。createUser
然后添加回调或高阶函数作为第二个参数。
这是创建用户时用作回调的高阶函数示例:
createUser
在视图模型中
fun createUser(userBody: UserBody, onUserCreated: (UserResponse) -> Unit) {
//Log.d("USERVIEWMODEL_TOP", "the first response:$userPayload")
scope.launch {
//userPayload = repository.createUser(userBody)
val userPayload: UserResponse = repository.createUser(userBody)
onUserCreated(userPayload)
//Log.d("USERVIEWMODELCHCK", "speak now:$userPayload")
}
}
为什么这样?因为
scope.launch{...}
类似于封闭环境,您必须以某种方式userPayload
从大括号内获取scope.launch{ ... }
。在您的解决方案中,您userPayload
从外部返回,scope.launch{}
对内部发生的事情一无所知{}
还要修改createUser
存储库中的函数:
createUser
在存储库中:
suspend fun createUser(userBody: UserBody): UserResponse {
return withContext(Dispatchers.IO) {
try {
val status = userApi.addUserAsync(userBody).await()
//Will be used as returend value.
status
} catch (t: Throwable) {
//Will be used as returned value - in case of error.
UserResponse()
}
}
}
为什么?原因同上。您正在从外部返回状态
withContext(Dispatchers.IO) {}
。所以由于我们想从内部返回一些东西withContext(Dispatchers.IO) {}
——我们需要在之前添加 return 语句withContext
。在这种情况下,最后一行try {}
或最后一行catch{}
(如果出现错误)将用作return
之前语句的返回值withContext(Dispatchers.IO) {}
现在您应该能够通过createUser
以下方式调用函数来接收片段中的响应:
分段
viewModel.createUser(userBody) { response ->
if (response.status == 200) {
Log.d("SIGNUP_FRAGMENT", "wat is here:${response}")
saveUserInfo(response)
findNavController().navigate(R.id.action_signUpFragment_to_verificationFragment)
} else {
Toast.makeText(
this.context,
"${response.status}, ${response.message}",
Toast.LENGTH_SHORT
).show()
}
}
推荐阅读
- java - 在取最大值(0,x)时对流中的元素求和?
- javascript - 给定数字数组的可能三角形数问题
- vba - VBA:Excel宏在调试中正确执行,但在执行时不运行子
- javascript - 在 React Native 中使用 Google Contacts Api
- jenkins - 使用 Jenkins 作业存储和查询键/值 (UUID)
- angularjs - 查看 mongodb 集合时,MEAN 堆栈未加载页面
- c# - C# chrome tab 获取索引
- python - 在 Flask 中将 GET 方法转换为 POST 方法
- javascript - 如何使用 javascript 搜索 PDF 文件标题和/或内容。
- c++ - 内存增加和字符串流?