DEV Community

Cover image for Retrieving a single value from the Room database
Tristan Elliott
Tristan Elliott

Posted on • Updated on

Retrieving a single value from the Room database

Introduction

  • This series is not going on the Android Room database. Anything I find cool about the Room database I will put here.

Youtube version

GitHub code

Before you get started

  • In order for this tutorial to be useful to you please make sure that you followed the tutorial, HERE, or at least have a database up and running on your android app.

Getting started

  • So this tutorial is going to focus on how you can retrieve a single value from Room database and display it to the UI. I want to stress this again, If you do not have a database up and running please follow the official Room code lab, HERE.

The DAO

  • Starting in the data access object(DAO), we all know this is the area where we specify the SQL queries and associate them with method calls. Since we want to retrieve one full row of the table, we make this request:
@Query("SELECT * FROM calf WHERE calf.id==:calfId")
     suspend fun findCalf(calfId:Long):Calf
Enter fullscreen mode Exit fullscreen mode
  • The code is pretty straight forward, the only thing that is worth pointing out is the suspend keyword. But before we can talk about this keyword we need to talk about Coroutines

Coroutines

  • As the documentation states: coroutine is an instance of suspendable computation, which means that code inside of a coroutines runs asynchronously. So are coroutines Kotlin's version of Threads? No they are not. Conceptually coroutines are similar to threads in that they take a block of code and run it asynchronously. But coroutines actually run on top of a threads and are actually not even bound to a specific thread. They can start on one thread and finish on another. A good visual representation of a coroutine can be found, HERE.
  • I also want to point out that code inside of a coroutine runs sequentially(This will be important later).

Suspend functions

  • Now that we have a basic understanding that a coroutine is a piece of asynchronous code, we can talk about the suspend keyword. The first thing to point out about a suspend function is that it can only be called from another suspend function or inside a coroutine. The main idea behind this function modifier is to be able to allow us to program more declaratively and to get away from the typical callback hell. Although, technically speaking under the hood, the Kotlin compiler will turn all the suspend functions into optimized callbacks for us.
  • When we see a suspend function, that function must be called from inside another suspend function or a coroutine.

Repository

  • The next layer inside this architecture is the repository layer. While not necessary it is considered a best practice to a repository layer. It's main job is to provide a clean API for data access to the rest of the application. The code in the repository layer will look like this:
suspend fun findCalf(calfId:Long):Calf{
        return calfDao.findCalf(calfId)
    }

Enter fullscreen mode Exit fullscreen mode
  • The code is nothing we have not seen before. The only thing to note is that we are calling the calfDao.findCalf(calfId) method which as we know is a suspend function, which means that findCalf() must also be a suspend function

ViewModel

  • This is where things start to get a little bit more complicated. For example, our method looks like this:
suspend fun findCalf(calfId:Long):Calf{
        val deferred:Deferred<Calf> = viewModelScope.async {
            repository.findCalf(calfId)
        }
        return deferred.await()
    }

Enter fullscreen mode Exit fullscreen mode
  • There are a lot of weird and fancy words, but lets start with async{...}. async is called a coroutine builder, remember that I said suspend functions need to be called inside of a coroutine or a suspend function well async{} creates a coroutine for us. Now each coroutine must have a coroutine scope, which is essentially the life time of the coroutine. For our code the coroutine scope is the viewModelScope, which is a specific scope provided to us by Android. viewModelScope.async{...} means that the code inside of this coroutine is scoped to this ViewModel and if ViewModel gets shut down then so does the coroutine.

  • I am sure you are probably use to launch{} instead of the async{}. The main difference between the two is that async returns what is called a Deferred object. This type of object is similar to a Promise of Future. Basically its an object that will return at some point in the future. With our code, it returns a Deferred<Calf> which is a deferred object that contains a Calf object. Ok but our function returns a calf, so how do we get our Calf outside of the deferred object? We do that by calling the await() method on the deferred object, which will make the function suspend while it waits for the method to return. Which means that this function must be a suspend function which means that this function must be called from a coroutine or another suspend function.

Connection to the UI

  • So this is another part of the blog post can get a little weird so listen up!!
  • We start inside of our Fragment class's onViewCreated() method and we know that we need to create a coroutine to call our findCalf() method on the ViewHolder, we do so like this:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

CoroutineScope(Main).launch {

  foundCalf = calfViewModel.findCalf(calfId)

        }


Enter fullscreen mode Exit fullscreen mode
  • The most important thing to point out is CoroutineScope(Main). This is how we can interact with the UI, Android does not allow us to interact with the UI if we are on a different thread besides the Main thread. So CoroutineScope(Main) switches our coroutine scope over to the Main thread. We can now use the Calf object stored inside of foundCalf to update our UI.

Conclusion

  • Thank you for taking the time out of your day to read this blog post of mine. If you have any questions or concerns please comment below or reach out to me on Twitter.

Top comments (0)