Home > Software engineering >  How do i get my retrofit to wait until its done before i start my recycler view
How do i get my retrofit to wait until its done before i start my recycler view

Time:10-30

I am trying to make my recycler view wait until my retrofit function is done. The retrofit function is stored in a view model while the recyler view is in my activity. I can get it to work with a delay but that does not seem like a good way to do it.

        GlobalScope.launch {
        suspend {
val txt = findViewById<TextView>(R.id.textbox)
            viewModel.getStaff()


            delay(10000)
            withContext(Dispatchers.Main) {
                Log.d("coroutineScope", "#runs on ${Thread.currentThread().name}")
                createRV(viewModel.pictureList, viewModel.actorList, viewModel.characterList, viewModel.houseList)

            }
        }.invoke()

and this is my retrofit function

suspend fun getStaff(){
    val retrofit = Retrofit.Builder()
        .baseUrl("http://hp-api.herokuapp.com/")
        .addConverterFactory(GsonConverterFactory.create())
        .build()
    val service = retrofit.create(HarryPotterApi::class.java)
    val call = service.staff()

    try {

        call.enqueue(object : Callback<Staff> {

            override fun onResponse(call: Call<Staff>, response: Response<Staff>) {

                if (response.code() == 200) {
                    val characterData = response.body()!!
             

                     pictureList.add(characterData[0].name)
                     actorList.add(characterData[0].name)
                    characterList.add(characterData[0].name)
                    houseList.add(characterData[0].name)
                }
            }
            override fun onFailure(call: Call<Staff>, t: Throwable) {

            }
        })}catch (e: IOException) {

        e.printStackTrace()
    }

}

CodePudding user response:

I suggest a better way. Rather than delay (10000), hide the recyclerView and use a placeholder view instead

When you are ready to display the recyclerView:

withContext(Dispatchers.Main) {

placeholderView.visibility = View.GONE
recyclerView.visibility = View.VISIBLE

                Log.d("coroutineScope", "#runs on ${Thread.currentThread().name}")
                createRV(viewModel.pictureList, viewModel.actorList, viewModel.characterList, viewModel.houseList)

            }

CodePudding user response:

Retrofit supports coroutines and suspend functions since 2.6.0, so you don't have to use callbacks and then somehow convert asynchronous call into suspendable (which is also possible). You can make HarryPotterApi.staff() itself suspendable and them make your whole code much simpler and synchronous, at the same time fixing your problem with waiting for getStaff() to finish.

I don't have your full code, but I assume HarryPotterApi.staff() is declared something like this:

fun staff(): Call<Staff>

Make it suspendable:

suspend fun staff(): Staff

Then use it synchronously:

suspend fun getStaff(){
    val retrofit = Retrofit.Builder()
        .baseUrl("http://hp-api.herokuapp.com/")
        .addConverterFactory(GsonConverterFactory.create())
        .build()
    val service = retrofit.create(HarryPotterApi::class.java)

    val characterData = service.staff()
    pictureList.add(characterData[0].name)
    actorList.add(characterData[0].name)
    characterList.add(characterData[0].name)
    houseList.add(characterData[0].name)
}

It may not be a fully working example, but I hope you get the idea.

  • Related