Home > Mobile >  Room Flow Always returns kotlinx.coroutines.flow.SafeFlow@c8abe2e
Room Flow Always returns kotlinx.coroutines.flow.SafeFlow@c8abe2e

Time:09-08

Initially i am getting list data from network and store it in room db.
It is One to Many Relationship. For that i have created Two Tables and One Relationship data class

Product Table :

@Entity(tableName = "Product")
data class Products (

    @PrimaryKey(autoGenerate = false)
    @ColumnInfo(name = "id")
    var id : Int = 0,

    @ColumnInfo(name = "name")
    var name  : String? = null,

    @ColumnInfo(name = "category_id")
    var category_id : String? = null,

    @ColumnInfo(name = "subcategory_id")
    var subcategory_id : String? = null,

    @ColumnInfo(name = "variants")
    var variants : List<Variants> = listOf()
)

Variant Table :

@Entity(tableName = "Variant")
data class Variants (

    @PrimaryKey(autoGenerate = false)
    @ColumnInfo(name = "id")
    var id : Int  = 0,

    @ColumnInfo(name = "product_id", index = true)
    var product_id : Int?  = null,

    @ColumnInfo(name = "measurement")
    var measurement : String?  = null,

    @ColumnInfo(name = "price")
    var price : String?  = null
)

Product With Variants ( Relationship between Two Tables )

  data class ProductWithVariants(
    @Embedded val product: Products,
    @Relation(
        parentColumn = "id",
        entityColumn = "product_id"
    )
    val variants: MutableList<Variants> 
)

Dao : I get the ProductsWithVariants data using query and also filter by subcategory_id

@Transaction
@Query("SELECT * FROM Product WHERE subcategory_id=:subcat")
fun getProductWithVariants(subcat:Int): Flow<MutableList<ProductWithVariants>>

ViewModel :

var productListN: Flow<MutableList<ProductWithVariants>> = flowOf(mutableListOf())

fun networkproductlist() = viewModelScope.launch(Dispatchers.IO) {
    productist.collectLatest {
        when (it) {
            Resource.Empty -> {
                Log.e("product", ""   "empty")
            }
            is Resource.Failure -> {
                Log.e("product", ""   "failure")
            }
            Resource.Loading -> {

            }
            is Resource.Success -> {
                val response = it.value
                for (i in 0 until response.data.size) {
                    val product: Products = response.data.get(i)
                    for (j in 0 until product.variants.size) {
                        variants = product.variants.get(j)
                    }
                }
                productsDao.deleteAllProducts()
                productsDao.insertProducts(response.data)
                productsDao.insertVariants(variants!!)
                val subcategoryid = SubCategoryList(response.data[0].subcategory_id!!.toInt())
                productsDao.insertSubCat(subcategoryid)
                productListN = productsDao.getProductWithVariants(response.data[0].subcategory_id!!.toInt())
                Log.e("product","product in room viewmodel : $productListN")
            }
        }
    }
}

As I said earlier , got the network response in success resource and insert products and variants in respective tables after that i insert the product subcategory in my database and get the list of ProductWithVariants by hit the getProductWithVariants() on the next line ..

The Problem here is now - i always get kotlinx.coroutines.flow.SafeFlow@f06e8a9 as a response of productlistN

Main Activity :

lifecycleScope.launch(Dispatchers.Main) {
    proadapter = ProductAdapter()
    binding.ProductRecyclerView.apply {
       adapter = proadapter
    }
}

lifecycleScope.launch(Dispatchers.Main) {
    viewModel.productListN.collect {
        println("Received UserInfo List $it")
        proadapter.setMutableArraylist(it)
        proadapter.notifyDataSetChanged()
    }
}

CodePudding user response:

I found a couple of issues in your code:

  • In ViewModel you use var productListN = ... and then reinitialize it with a new object productListN = productsDao.getProductWithVariants(response.data[0].subcategory_id!!.toInt()). You shouldn't reinitialize it, you must use the same object. You can try to use StateFlow or SharedFlow to emit data:
val productListN: Flow<MutableList<ProductWithVariants>> = StateFlow(mutableListOf())
...
productListN.value = ...

  • In Activity initialize proadapter and binding.ProductRecyclerView outside of launch function, and for collecting Flow data just use lifecycleScope.launch { ... }:
proadapter = ProductAdapter()
binding.ProductRecyclerView.apply {
    adapter = proadapter
}

lifecycleScope.launch {
    viewModel.productListN.collect {
        println("Received UserInfo List $it")
        proadapter.setMutableArraylist(it)
        proadapter.notifyDataSetChanged()
    }
}
  • Related