Как я могу получить ответ от моего запроса POST о модификации моего фрагмента? - PullRequest
1 голос
/ 10 апреля 2020

Моя цель - захватить или получить ответ из моей viewModel в мой фрагмент signUp, когда я нажимаю кнопку signUp и перехожу к фрагменту проверки , если response.status имеет значение true .

Когда я нажимаю на кнопку регистрации в моем 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)

I видел этот ответ, используя журнал; ответ не доходит до моего фрагмента подписи.

Вот мой код репозитория ниже:

 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


    }
}

Вот мой код viewModel:

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!!) }
    }
}

Ответы [ 2 ]

0 голосов
/ 10 апреля 2020
userPayload = repository.createUser(userBody)

Эта строка в вашей ViewModel будет выполняться в фоновом потоке и, следовательно, является асинхронной. Чтобы опубликовать sh "userPayload" объект в вашем фрагменте, вам нужно использовать LiveData, как это

//Define a mutablelivedata property in your ViewModel
public var userPayloadLiveData = MutableLiveData<UserResponse>()

Из подпрограммы внутри вашей ViewModel вы должны опубликовать свой ответ на вивататы как таковые

userPayload = repository.createUser(userBody)
userPayloadLiveData.postValue(userPayload)

Из вашего фрагмента вы должны наблюдать "userPayloadLiveData" для асинхронных c изменений в значение.

viewModel.userPayloadLiveData.observe(this, Observer { userResponse ->

    //this code will run after network call and now safe to do UI stuff.
    //userResponse is your response object

})

Чтобы узнать больше о том, как работает LiveData или MutableLiveData, обратитесь к документам androidx MutableLiveData

0 голосов
/ 10 апреля 2020

Это плохой подход к созданию экземпляра переменной (например: status, userPayload) с каким-либо фиктивным объектом, а затем к изменению его в ответ на запрос другого метода, а затем к возврату через функцию return. Вам лучше создать его экземпляр с нулевым значением и вернуть ответ на вызывающую функцию через callback. Тогда, если у вас нет значения немедленно, что-то идет не так.


Приведенный выше подход является источником вашей проблемы. Потому что функция createUser возвращает DummyObject, а не реальный объект из Retrofit. Чтобы это исправить, вам нужно удалить функцию return из метода createUser. А затем добавьте функцию обратного вызова или функцию более высокого порядка в качестве второго параметра.

Вот пример функции более высокого порядка, которая используется в качестве функции обратного вызова при создании пользователя:

createUser в ViewModel

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 из outisde 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) {} - нам нужно добавить оператор возврата как раз перед 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()
    }
}
...