Reputation: 159
I'm new to android and room. I'm trying to make a local db but I'm struggling at this point where the database is not empty as the image below proves. But when I try to select any data it returns an empty list or null values. Note that the insert query works fine.
Code: Entity:
@Entity(tableName = "product_table")
@Parcelize
data class Product(
@PrimaryKey
@SerializedName("id")
val id : String,
@SerializedName("title")
val title : String,
@SerializedName("price")
val price : String,
@SerializedName("category")
val category : String,
@SerializedName("description")
val description : String,
@SerializedName("image")
val image : String,
val color : String,
val size : String
): Parcelable
Dao:
@Dao
interface CartDao {
@Query("SELECT * FROM product_table")
fun get_all_carts(): LiveData<List<Product>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert_item_to_cart(product: Product) : Long
@Delete
suspend fun delete_item_from_cart(product: Product)
@Query("Delete FROM product_table")
fun delete_all_cart()
}
Database:
@Database(entities = [Product::class], version = 1)
abstract class ProductDatabase : RoomDatabase() {
abstract fun productDao(): CartDao
companion object{
@Volatile
private var INSTANCE: ProductDatabase? = null
fun getDataseClient(context: Context) : ProductDatabase {
if (INSTANCE != null) return INSTANCE!!
synchronized(this) {
INSTANCE = Room
.databaseBuilder(context, ProductDatabase::class.java, "product_database")
.fallbackToDestructiveMigration()
.build()
return INSTANCE!!
}
}
}
}
Repository:
class CartRepository {
companion object {
var productDatabase: ProductDatabase? = null
var product: LiveData<Product>? = null
fun initializeDB(context: Context) : ProductDatabase {
return ProductDatabase.getDataseClient(context)
}
fun get_all_data(context: Context) : List<Product> {
productDatabase = initializeDB(context)
var temp_list = emptyList<Product>()
CoroutineScope(Dispatchers.IO).launch {
temp_list = productDatabase!!.productDao().get_all_carts()
}
return temp_list
}
fun get_first_item(context: Context, input_id : String) : Product {
productDatabase = initializeDB(context)
var temp_item : Product = Product("","","","","","","","")
CoroutineScope(Dispatchers.IO).launch {
temp_item = productDatabase!!.productDao().get_item(input_id)
}
return temp_item
}
}
}
View Model:
@HiltViewModel
class CartFragmentViewModel @Inject constructor(
private val productDao : CartDao
) : ViewModel() {
var products_list : MutableLiveData<List<Product>>
init {
products_list = MutableLiveData()
}
fun get_all_products(context: Context) : List<Product>{
return CartRepository.get_all_data(context)
}
fun get_first_item(context: Context, input_id : String) : Product{
return CartRepository.get_first_item(context, input_id)
}
}
Fragment:
class CartFragment @Inject constructor(
) : Fragment(R.layout.cart_fragment_layout) {
lateinit var cart_list : List<Product>
val cart_adapter = CartRecyclerViewAdapter()
val viewModel by activityViewModels<CartFragmentViewModel>()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
rv_cart.adapter = cart_adapter
rv_cart.layoutManager = LinearLayoutManager(
activity?.applicationContext,
LinearLayoutManager.VERTICAL,
false
)
rv_cart.setHasFixedSize(true)
/*cart_list = viewModel.get_all_products(activity?.applicationContext!!)
cart_adapter.submitList(
cart_list
)
cart_adapter.notifyDataSetChanged()
Log.d(TAG, "Fetched Data: {${cart_list.get(1).title}}")*/
var p = viewModel.get_first_item(activity?.applicationContext!!, "1")
cart_adapter.submitList(
listOf(
p
)
)
cart_adapter.notifyDataSetChanged()
var s = p.title
Log.d(TAG, "Fetched Data: {$s}")
/*viewModel.get_first_item(activity?.applicationContext!!).observe(viewLifecycleOwner, Observer {
cart_adapter.submitList(listOf(it))
cart_adapter.notifyDataSetChanged()
})*/
//viewModel.get_first_item(activity?.applicationContext!!)
}
}
There are many comments and logs in the Fragment
Class for the sake of trying to figure what the problem is. I can't really know what is happening and when I use LiveData
as return type of dao get functions the app crashes. Hope someone can help me out and thanks for your attention.
Upvotes: 4
Views: 2453
Reputation: 11
To use a LiveData with room, firstly, you should attach an observer to the live data.
So instead of returning the value of LiveData from the Repository methods, you should return the Live Data object itself, And then observe that Livedata in your Viewmodel class.
Upvotes: 1
Reputation: 977
The problem with your CartRepository methods.
fun get_first_item(context: Context, input_id : String) : Product {
productDatabase = initializeDB(context)
var temp_item : Product = Product("","","","","","","","")
CoroutineScope(Dispatchers.IO).launch {
temp_item = productDatabase!!.productDao().get_item(input_id)
}
return temp_item
}
In the above method, you are fetching an item in a background thread which means it goes into another thread and allows the return temp_item to always returns immediately, without blocking the code to wait for a result so that's why you are getting null and or empty list.
Solution is :
Make all database operation methods in CartRepository as suspended, see below: Note: I use an object instead of class
object CartRepository {
var productDatabase: ProductDatabase? = null
fun initializeDB(context: Context) : ProductDatabase {
return ProductDatabase.getDataseClient(context)
}
suspend fun get_all_data(context: Context) : List<Product> {
productDatabase = initializeDB(context)
return productDatabase!!.productDao().get_all_carts()
}
suspend fun get_first_item(context: Context, input_id : String) : Product {
productDatabase = initializeDB(context)
return productDatabase!!.productDao().get_item(input_id)
}
}
And in your viewModel call this suspend function in viewModelScope like below:
@HiltViewModel
class CartFragmentViewModel @Inject constructor(
private val productDao : CartDao
) : ViewModel() {
.....
var productData = MutableLiveData<Product>()
fun get_first_item(context: Context, input_id: String) {
viewModelScope.lauch(Dispatchers.IO){
val data = CartRepository.get_first_item(context, input_id)
withContext(Dispatchers.Main){
productData.value = data
}
}
}
....
In your fragment call get_first_item first then observe you data productData and you can do the same things for other database operations also by following all steps.
I hope this will help you if you dont understand any code just let me know in the comments and please ignore the typos
Upvotes: 1