Updating Recyclerview adapter from suspend function

842 Views Asked by At

I'm trying to load and display books from the books api but the information doesn't display. I was able to get it to display if I used the debugger and step through but not from starting off.

    val client = OkHttpClient()
    val request = Request.Builder()
        .url(url)
        .build()

    client.run {
        newCall(request).enqueue(object : Callback {
            override fun onFailure(call: okhttp3.Call, e: IOException) {
                e.printStackTrace()
            }

            override fun onResponse(call: okhttp3.Call, response: Response) {
                if (!response.isSuccessful) {
                    System.err.println("Response unsuccessful")
                    return
                }
                val response = response.body?.string()
                val books = response?.let { parse(it) }
                if (books != null) {
                    list.addAll(books.bookItems)
                }
            }
        })
        delay(500)
    }
    return list
}

Edit: Just needed to increase the delay time and remove renderBooks() call

2

There are 2 best solutions below

1
Sơn Phan On BEST ANSWER

You call presenter.getBooks before the fragment's view is initialized. Try place it inside onViewCreated.

0
Michael Krussel On

That delay seems very wrong. You are making all requests for data take 500 milliseconds. If it takes longer you get no data, if it takes less time then you are needlessly waiting.

I assume this works when using the debugger because you made the function wait longer before the return statement.

The correct solution is to use suspendCoroutine.

return suspendCoroutine { cont ->
   val client = OkHttpClient()
   val request = Request.Builder()
       .url(url)
       .build()

   client.run {
       newCall(request).enqueue(object : Callback {
           override fun onFailure(call: okhttp3.Call, e: IOException) {
              cont.resumeWithException(e)
           }

           override fun onResponse(call: okhttp3.Call, response: Response) {
               if (!response.isSuccessful) {
                   System.err.println("Response unsuccessful")
                   cont.resume(emptyList())
               }
               val items = response.body?.string()
                        ?.let { parse(it) }
                        ?.bookItems
                        .orEmpty()
               cont.resume(items)
           }
       })
    }
}

You might need to wrap the call to string in a try catch to catch any IOException from reading the input string.