I would like to have a system to call API (Retrofit) with cache (in Room), with just coroutines (without LiveData and NetworkBoundResource).
So worflow is:
- Check data in db
- if present show it
- if not:
- Call API
- Save data in db
- show data
Problem app blocked in "Call API" step, here the stack
nativePollOnce:-1, MessageQueue (android.os) next:326, MessageQueue (android.os) loop:160, Looper (android.os) main:6669, ActivityThread (android.app) invoke:-1, Method (java.lang.reflect) run:493, RuntimeInit$MethodAndArgsCaller (com.android.internal.os) main:858, ZygoteInit (com.android.internal.os)
Retrofit service:
interface ProductService {
@GET("products")
suspend fun getProducts(): Response<List<Product>>
}
DAO Room:
@Dao
interface ProductDao {
@Query("SELECT * FROM Product ORDER BY price")
suspend fun getProducts(): List<Product>
@Transaction
@Insert(entity = Product::class)
suspend fun insertProducts(products: List<Product>)
}
My fragment:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
productService = createProductService()
productDao = MyDatabase.getDatabase(requireContext()).productDao()
CoroutineScope(Dispatchers.Main).launch {
getProducts()
}
}
private suspend fun getProducts() {
progressBar.visibility = View.VISIBLE
recyclerViewProducts.visibility = View.GONE
var products = withContext(Dispatchers.IO){ productDao.getProducts() }
if(products.isEmpty()) {
val response = withContext(Dispatchers.IO) { productService.getProducts() }
if(response.isSuccessful && response.body() != null) {
products = response.body()!!
withContext(Dispatchers.IO) { productDao.insertProducts(products) }
}
}
withContext(Dispatchers.Main) {
progressBar.visibility = View.GONE
recyclerViewProducts.visibility = View.VISIBLE
recyclerViewProducts.apply {
layoutManager = LinearLayoutManager(context)
// set the custom adapter to the RecyclerView
adapter = ProductsAdapter(products, this@ListProductFragment)
}
}
}