Akram Baratov
Akram Baratov

Reputation: 163

Android Room: Adding and removing works infinitely

I use in project RecyclerView, Room DB and trying to make a function to add a record to table or remove if exists by clicking button. But the main problem is that function executes infinitely (adds, removes and again).

Here is code:

Fragment

override fun saveDeleteCover(image: ImageView, cover: Cover) {
    viewModel.checkIfCoverInDatabase(cover).observe(viewLifecycleOwner, { savedCover ->
        //If savedCover is null then save item to table. Otherwise remove
        if(savedCover == null) {
            viewModel.saveCover(cover)
            Toast.makeText(context, "Added to favorite", Toast.LENGTH_SHORT).show()
        } else {
            viewModel.deleteCover(cover)
        Toast.makeText(context, "Removed from favorite", Toast.LENGTH_SHORT).show()
        }
    })
}

ViewModel

fun saveCover(cover: Cover) = viewModelScope.launch {
    coverRepository.upsert(cover)
}

fun deleteCover(cover: Cover) = viewModelScope.launch {
   coverRepository.deleteCover(cover)
}

fun checkIfCoverInDatabase(cover : Cover) = coverRepository.checkCoverInDb(cover.textId)

Repository

suspend fun upsert(cover : Cover) = db.coversDao().upsert(cover)

suspend fun deleteCover(cover: Cover) = db.coversDao().deleteCover(cover)

fun checkCoverInDb(textId: String) : LiveData<Cover> {
    return db.coversDao().checkCover(textId = textId)
}

And DAO

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun upsert(cover : Cover) : Long

@Delete
suspend fun deleteCover(cover: Cover)

@Query("SELECT * FROM covers WHERE textId=:textId")
fun checkCover(textId: String) : LiveData<Cover>

Upvotes: 0

Views: 101

Answers (3)

Muhammad Ali
Muhammad Ali

Reputation: 97

Well, you don't need to check whether it's in a database or not. just pass CoverId in deleteCover Method and run query. but still, if you have a case to check then below is the way. You don't need live data call

Your DAO would be like

@Query("SELECT * FROM covers WHERE textId=:textId")
fun checkCover(textId: String) : Cover?

@Query("DELETE FROM covers WHERE textId=:Id")
suspend fun deleteCover(Id: String)

REPO would be

suspend fun deleteCover(id: String) = db.coversDao().deleteCover(id)
fun checkCoverInDb(textId: String) : Cover? {
      return db.coversDao().checkCover(textId = textId)
}

and your method would be like

override fun saveDeleteCover(image: ImageView, cover: Cover) {
 val cover =  viewModel.checkCoverInDb(cover.textId)
 if(cover == null) {
        viewModel.saveCover(cover)
        Toast.makeText(context, "Added to favorite", Toast.LENGTH_SHORT).show()
    } else {
        viewModel.deleteCover(cover.textId)
    Toast.makeText(context, "Removed from favorite", Toast.LENGTH_SHORT).show()
    }
 }

Upvotes: 1

androidLearner
androidLearner

Reputation: 1702

If the function executes infinitely before click the button ,move the observer code into onclick().

Upvotes: 0

R&#243;bert Nagy
R&#243;bert Nagy

Reputation: 7642

You probably don't need a reactive pattern, liveData for your saveDeleteCover function. Currently why you get an infinite save/remote operation is because:

  1. Check database emits new value - null
  2. You save the cover
  3. Check database gets triggered again, and emits new - cover
  4. You delete cover

Then the steps get repeated from step 1.

I suspect you're trying to favorite/unfavorite an item based on a click, so you could just simply call:

override fun saveDeleteCover(image: ImageView, cover: Cover) {
        if(viewModel.checkIfCoverInDatabase(cover).value == null) {
            viewModel.saveCover(cover)
            Toast.makeText(context, "Added to favorite", Toast.LENGTH_SHORT).show()
        } else {
            viewModel.deleteCover(cover)
        Toast.makeText(context, "Removed from favorite", Toast.LENGTH_SHORT).show()
        }
}

That way your operation will run only on the latest value

Upvotes: 0

Related Questions