dazai
dazai

Reputation: 716

How can I retrieve a single object from room database?

I'm trying to retrieve a single object from my room database given its title but when I get to the fragment where I want this to happen, I have no way to access the object's fields. The method I'm trying to use is retrieveMovie but the observer shows that it = List! and for some reason I cannot get the movie given its title and then get its fields to bind them to my view. How can I do this?

I tried accessing the movie with it's index(0) but the second movie I click on causes an app crash that returns: 'java.lang.IndexOutOfBoundsException: Index: 0, Size: 0'

This is the fragment's part:

if(arguments != null){
            val titleString = arguments?.getString("Title")

            //observe viewmodel
            if (titleString != null) {
                mMoviesViewModel.retrieveMovie(titleString).observe(viewLifecycleOwner, Observer { movie ->
                    itemTextTitle.text = movie.title //this doesn't work
                })
            }
        } else {
            //display error message if arguments are null
            Toast.makeText(context, "Error loading content", Toast.LENGTH_SHORT).show()
        }

This is the db's viewmodel:

class MoviesViewModel(application: Application): AndroidViewModel(application) {

    val readAllData: LiveData<List<Movies>>
    private val repository: MoviesRepository

    init {
        val moviesDao = MoviesDatabase.getDatabase(application).moviesDao()
        repository = MoviesRepository(moviesDao)
        readAllData = repository.readAllData
    }

    fun addMovie(movie: Movies) {
        viewModelScope.launch(Dispatchers.IO) {
            repository.addMovie(movie)
        }
    }

    fun movieExists(id: Int): Boolean{
        viewModelScope.launch(Dispatchers.IO){
            repository.movieExists(id)
        }
        return true
    }

    fun retrieveMovie(title: String): LiveData<List<Movies>> {
        return repository.retrieveMovie(title)
    }
}

This is the db's repository:

class MoviesRepository (private val moviesDao: MoviesDao) {

    val readAllData: LiveData<List<Movies>> = moviesDao.readALlData()

    fun addMovie(movie: Movies){
        moviesDao.addMovie(movie)
    }

    fun movieExists(id:Int){
        moviesDao.movieExists(id)
    }

    fun retrieveMovie(title:String): LiveData<List<Movies>> {
        return moviesDao.retrieveMovie(title)
    }
}

Dao:

package com.app.challengemovieapp.db

import androidx.lifecycle.LiveData
import androidx.room.*
import com.app.challengemovieapp.model.Movie
import kotlinx.coroutines.flow.Flow

@Dao
interface MoviesDao {

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    fun addMovie(movie:Movies)

    @Query("SELECT * FROM movie_table ORDER BY id ASC")
    fun readALlData(): LiveData<List<Movies>>

    @Query("SELECT EXISTS(SELECT * FROM movie_table WHERE id = :id)")
    fun movieExists(id : Int) : Boolean

    @Query("SELECT * FROM movie_table WHERE title = :title")
    fun retrieveMovie(title:String): LiveData<List<Movies>>

}

Upvotes: 1

Views: 3221

Answers (2)

Eugene Troyanskii
Eugene Troyanskii

Reputation: 892

To get a single entity you can use limit. Here is an example

@Query("SELECT * FROM movie_table WHERE title = :title LIMIT 1")
fun retrieveMovie(title:String): LiveData<Movies>

Upvotes: 2

rohan ghosh
rohan ghosh

Reputation: 177

so the reason why you can't access the Movie object is cause you are mentioning this.

@Query("SELECT * FROM movie_table WHERE title = :title")
fun retrieveMovie(title:String): LiveData<List<Movies>>.

So LiveData is returning a List of Movie objects.

what you can do is

it.get(0).getTitle()

It should work.

Upvotes: 0

Related Questions