{{announcement.body}}
{{announcement.title}}

Introduction to Android App Development With Kotlin: Store Data in Database (Part 8)

DZone 's Guide to

Introduction to Android App Development With Kotlin: Store Data in Database (Part 8)

Learn how to store data in your database using Kotlin.

· Java Zone ·
Free Resource

In this tutorial, we will instantiate the Room database using the singleton pattern. We will use our first coroutine and finally persist the data.

Having set up our Room database in the previous tutorial, it’s the time to insert some data into it. Before we can use the database, however, there’s just one more step we must carry out before it’s fully functional — we must instantiate it.

Instantiate Room

In order to instantiate the Room database, we will implement the singleton pattern. If you’re not familiar with what the singleton pattern is, in a few words, it ensures that there’s only ever one instance of a certain object for the entire app. Since we only have one database in our app, it’s appropriate that we only have one instance of it. Anything more than that would be a waste of resources.

Inside the AppDatabase class, insert the following code:

 companion object {
        private var INSTANCE: AppDatabase? = null

        fun getInstance(context: Context): AppDatabase? {
            if (INSTANCE == null) {
                synchronized(AppDatabase::class) {
                    INSTANCE = Room.databaseBuilder(context.applicationContext,
                        AppDatabase::class.java, "movie-database")
                        .build()
                }
            }
            return INSTANCE
        }

        fun destroyInstance() {
            INSTANCE = null
        }
    }


Whenever we call the method getInstance(), the instance will be created if it hasn’t been created yet. Otherwise, it will return the already created instance.

The reason you see the synchronized method there is to be extra certain that no more than one instance gets created. If we didn’t use synchronize, it would be possible for two different threads to call the  getInstance() method at almost the same time and successfully create two instances of the database, which would not be desirable.

With the singleton of our database available for our use, let’s gain access to it inside the  NewMovieViewModel.

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

    private val mDb: AppDatabase? = AppDatabase.getInstance(application)

}


Notice that the mDb member variable is set to private. The reason for this is that we do not want to expose the database directly to the view. The view will call an appropriate method inside the ViewModel, which will then interact with the database.

Store Data

To store the data, we need a method that will accept user input of String type (movie title) and store it in the database. Let’s try it:

   fun storeMovie(title: String) {

        val movie = Movie()
        movie.name = title
        mDb?.movieDao()?.insert(movie)

    }


Now, let’s call this method in our NewMovieFragment inside the onViewCreated method after the validation is done and see what happens.

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)


        button.setOnClickListener {
            val input = editText.text.toString().trim()

            if (input.isEmpty()) {
                Toast.makeText(activity, "Title required", Toast.LENGTH_SHORT).show()
                return@setOnClickListener
            }

            if (input.length > 30) {
                Toast.makeText(activity, "Title too long", Toast.LENGTH_SHORT).show()
                return@setOnClickListener
            }

            mViewModel.storeMovie(input)

            Toast.makeText(activity, "$input entered", Toast.LENGTH_SHORT).show()
            listener?.goToMovieListFragment()
        }
    }


The only new line here is the  mViewModel.storeMovie(input). If you run the app now, type in a "test" movie title and hit the “Add” button. Unfortunately, our app is going to crash. You should receive the following stack:

Image title

As per the message in the exception, Android will tell us that we “Cannot access database on the main thread since it may potentially lock the UI for a long period of time.”

This is a good thing. Room prevents us from running queries on the main thread to protect the user from potentially slow apps. Because of this, we must spin up a background thread, which will not lock the UI, and carry out the operation there.

To achieve this, we will use Kotlin’s coroutines.

Coroutines

Coroutines are super simple to use once you know what you’re doing. I will show you an easy way to spin up a coroutine and execute our database call without a crash.

To use coroutines, we must import them into our project, in build.gradle (app) add:

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.1'


Then, go back to the  NewMovieViewModel and surround the database insert operation with  GlobalScope.launch { }.

Run the app and see what happens! Yes, no crash. We have successfully stored a movie title in a database. How do you know? Well, unfortunately, we haven’t implemented a fetch from the database function just yet, so we can’t tell for sure. You just have to take my word for it.

Conclusion

We have finally used our database and persisted some data for later use. Unfortunately, there’s no visible results of us storing the data yet. Therefore, in the next tutorial, we will fetch the data from the database to prove that we really are saving the data.

Complete working code can be found in this GitHub repo where each lesson is tagged appropriately.

Topics:
android development ,kotlin 1.3 ,coroutines ,room database ,store data ,app development ,java ,tutorial ,kotlin

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}