Room android kotlin coroutines

Room android kotlin coroutines

Room is a part of the Android Architecture components which provides an abstraction layer over SQlite which allows for a more robust database acces while still providing the full power of SQlite. You can read about Room in details here.

Room 2.1 (SQLite Persistence Library) added the support for coroutines. Now you can add the suspend keyword to DAO class methods and ensures that they are not executed in the MainThread.

Coroutines are light-weight threads. They are launched with launch coroutine builder in a context of some CoroutineScope.

LiveData is an observable data holder, part of the Android Jetpack. LiveData considers an observer, which is represented by the Observer class, to be in an active state if its lifecycle is in the STARTED or RESUMED state. LiveData only notifies active observers about updates.

First, we need to add the needed dependencies that will enable us to use the Room library. We can do so with some simple lines in the build.gradle (Module:app) file. Last version of Room here. Last version of Lifecycle here.

The Room library consists of 3 major components: Entity, DAO (Database Access Object), Database.

The Entity represents a table within the database and has to be annotated with @Enity . Each Entity consist of a minimum of one field has to define a primary key.

In Room you use DAO to access and manage your data. The DAO is the main component of Room and includes methodes that offer access to your apps database it has to be annotated with @Dao . DAOs are used instead of query builders and let you seperate differend components of your database e.g. current data and statistics, which allows you to easily test your database.

Serves as the database holder an is the main accespoint to your relational data. It has to be annotated with @Database and extents the RoomDatabase . It also containes and returns the Dao (Database Access Object).

This is a class where we will check whether to fetch data from API or local database, or you can say we are putting the logic of database fetching in this class.

This is the part of lifecycle library; this will help you to provide data between repository and UI. This survives the data on configuration changes and gets the existing ViewModel to reconnect with the new instance of the owner.

SQLite debug tools

  • Stetho is a debug bridge for Android that allows you to connect to a device and to inspect your app using Chrome Developer Tools.
  • SQLScout is a plugin for Android Studio and Intellij IDEA which allows you to connect to SQLite databases, browse tables and schemes.
  • Liya
  • SQLPro for SQLite

Источник

Room Database with MVVM and Kotlin Coroutines Android

Aung Kyaw Myint

Jul 10, 2019 · 4 min read

We will be developing a simple chat app like the one above with MVVM architecture using Room Database and Kotlin Coroutines. Let’s get started.

build.gradle

First, modify project/build.gradle like this:

And then app/build.gradle like this:

Layout

Create MainActivity and change the layout for activity_main like this:

We need a layout for ViewHolder inside RecyclerView. Let’s create one.

Entity

Now let’s start from the very basic: object(model) we gonna use for this app.

Note that in Room, we have to m a rk our object as Entity for a specific table. By default, Room uses the class name as the database table name. If you want the table to have a different name, set the tableName property of the @Entity annotation. Details can be found here.

When working with Room, there’s Dao ( Data Access Object) which is the main class where you define your database interactions. They can include a variety of query methods.

Instead of running queries on the database directly, you are highly recommended to create Dao classes. Using Dao classes will allow you to abstract the database communication in a more logical layer which will be much easier to mock in tests (compared to running direct sql queries). It also automatically does the conversion from Cursor to your application classes so you don’t need to deal with lower level database APIs for most of your data access.

Room also verifies all of your queries in Dao classes while the application is being compiled so that if there is a problem in one of the queries, you will be notified instantly.

The class marked with @Dao should either be an interface or an abstract class. At compile time, Room will generate an implementation of this class when it is referenced by a Database .

An abstract @Dao class can optionally have a constructor that takes a Database as its only parameter.

Читайте также:  Виртуальные ассистенты для андроид

It is recommended to have multiple Dao classes in your codebase depending on the tables they touch.

In getMessages() function, we are returning list of message in LiveData format which is one of MVVM architecture. We want the data to be live cycle aware. Whenever there’s a lifecycle change in our app, our data will be updated.

Database

Room Database creation is like this:

In our database, we have only one entity (object), version 1. ExportSchema is a boolean for telling Room that we want to export our schema to a folder. Default value is true. Even though it is not mandatory, it is a good practice to have version history in your codebase and you should commit that file into your version control system (but don’t ship it with your app!). In this case, I am setting false.

Repository

Now let’s create a repository where we can get the data from. You can think of repository as the single access point for getting the data. The class will include all the functions from which we can get all the data.

When we get the messages, we are already returning LiveData in Dao. So we don’t need to get the data from background thread. But when we set the message, the interaction with database cannot be done from Main (UI) thread. So we need to get it from background thread. Here comes Kotlin Coroutines. Coroutines is basically AsyncTask but it’s cleaner and more efficient. This article will be a great way to start learning Coroutines. As you can see we extend CoroutineScope and override CoroutineContext to operate in Main Thread. In setMessageBG() function, we make it suspend function and we call the function from Dao from background thread (Dispatcher.IO). After that, we call setMessageBG() in setMessage() from Main Thread because we are operating in Coroute Scope from which launch function extends.

ViewModel

Next comes ViewModel class which is designed to store and manage UI-related data in a lifecycle conscious way. The ViewModel class allows data to survive configuration changes such as screen rotations. Detailed explanation can be found here.

Adapter

We gotta create a Adapter for use with recyclerview. Before we do this, to achieve slide in animation, we have to create animation first. Create anim folder in res folder and add item_animation_fall_down.xml.

You can see that every time we’re binding the view, we’re setting the animation. You can choose whatever animation you like.

MainActivity

Last but not least. It’s time for MainActivity. Let’s do this.

If you don’t want the recyclerview to refresh from top, you have to set stackFromEnd to true for layoutManager. Otherwise everytime you add a new message to the list, it will be refreshed from the top. If you notice it, we also set this attribute in recyclerview inside activity_main.xml. Apparently, it’s not enough and you also gotta set it inside the code.

That’s it folks. Hope you enjoy it. Clap it if you like it.

Источник

Room 🔗 Coroutines

Add some suspense to your database

Room 2.1 adds support for Kotlin coroutines. DAO methods can now be marked as suspending to ensure that they are not executed on the main thread. Read on to see how to use this, how it works under the hood and how to test this new functionality.

Add some suspense to your database

To use coroutines and Room in your app, update to Room 2.1 and add the new dependency to your build.gradle file:

You’ll also need Kotlin 1.3.0 and Coroutines 1.0.0 or newer.

You can now update your DAO methods to use suspension functions:

@Transaction methods can also be suspending and they can call other suspending DAO functions:

You can also call suspension functions from different DAOs inside a transaction:

You can provide executors (by calling setTransactionExecutor or setQueryExecutor when you’re building your database) to control the threads they run on. By default this will be the same executor used for running queries on the background thread.

Testing DAO suspension functions

Testing a DAO suspending function is no different from testing any other suspending function. For example, to check that after inserting a user we are able to retrieve it, we wrap the test in a runBlocking block:

Under the hood

To see what’s under the hood, let’s take a look at the DAO class implementation Room generates for a synchronous and for a suspending insert:

For the synchronous insert, the generated code starts a transaction, executes the insert, marks the transaction as successful and ends it. The synchronous method will just execute the insert on whatever thread it’s called from.

Now let’s see how adding the suspend modifier changes things:

The generated code ensures that the insert happens off of the UI thread. In our suspend function implementation, the same logic from the synchronous insert method is wrapped in a `Callable`. Room calls the `CoroutinesRoom.execute` suspend function, which switches to a background dispatcher, depending on whether the database is opened and we are in a transaction or not. Here’s the implementation of the function:

Case 1. The database is opened and we are in a transaction

Here we just immediately execute the callable — i.e. the actual insertion of the user in the database

Читайте также:  Dev tool для android

Case 2. Otherwise

Room makes sure that the work done in the Callable#call method is performed on a background thread.

Room will use different Dispatchers for transactions and queries. These are derived from the executors you provide when building your Database or by default will use the Architecture Components IO executor. This is the same executor that would be used by LiveData to do background work.

If you’re interested to check out the implementation, check out the CoroutinesRoom.java and RoomDatabase.kt

Start using Room and coroutines in your app, the database work is guaranteed to be run on a non-UI Dispatcher. Mark your DAO method with the suspend modifier and call them from other suspend functions or coroutines!

Источник

Room 🔗 Flow

Coroutines support in Room has been increasing at every release: Room 2.1 added coroutines support for one-shot read / write operations and with Room 2.2 we now have support for observable reads with Flow enabling you to get notified of changes in your database.

Flow in action

Let’s say that we have a database of dogs, where the name is the primary key, therefore, we can’t have 2 dogs with the same name in the database.

To display a full list of dogs with all of their info we’d write a query like this in our DAO:

Because the barking volume of a dog can change over time and we want to make sure that our UI is up to date, then we want to get notified of every change that happens in the Dogs table: new dogs added, dogs removed or updated. To achieve this, we update the query to return Flow :

Like this, whenever a dog in the database is updated, then the entire list of dogs is emitted again. For example, let’s say that we have the following data in the database:

When we first call getAllDogs , our Flow will emit:

If Bandit gets excited and his bark volume is updated to 6: (Bandit, 12, 6) , the Flow will emit again, with the entire content of the dogs table with the latest values:

Now let’s say that we can open a dog details in a new screen. Because we also want to ensure we always have the latest data on the dog and get updates in real time, we return a Flow :

Now, if we call getDog(«Frida») , Flow will return one object: (Frida, 11, 3) .

Whenever any changes are made to the table, independent of which row is changed, the query will be re-triggered and the Flow will emit again. So if Frida gets updated, we will receive the latest info.

However, this behaviour of the database also means that if we update an unrelated row, like Bandit, our Flow will emit again, with the same result: (Frida, 11, 3) . Because SQLite database triggers only allow notifications at table level and not at row level, Room can’t know what exactly has changed in the table data, therefore it re-triggers the query defined in the DAO. In your code, use Flow operators like distinctUntilChanged , to ensure that you only get notified when the data you’re interested in has changed:

Start getting notified of the changes in your database by using observable reads with Flow ! Together with other coroutines support added in Jetpack libraries like lifecycle-aware coroutine scopes, suspend lifecycle-aware coroutines or the transformation from Flow to LiveData , you can now use coroutines and Flow throughout your entire application.

To find out more about using Flow in your app, check out this post on the lessons learned while using Flow in the Android Dev Summit 2019 app.

Источник

RoomDB in android with Kotlin-Coroutines

Oct 10 · 5 min read

The Room is an Android persistence library which provides an abstraction layer over SQLite.

Room is an ORM (Object Relational Mapper) for mapping our database objects in android. It is part of the Architecture Components.

This is the perfect choice when your application needs to store the user’s data locally to handle the case when the user goes offline or any network failure happens.

Components of RoomDB

  • Entity — A class that describes a database table when working with Room
  • DAO (Data Access Object) — A mapper of SQL queries to functions
  • Database — For on device storage
  • Repository — Primarily used to manage multiple data sources
  • ViewModel — Communication center between data and UI

Pre-requisites

  • SQLite database and the SQLite query language
  • Basic idea of Kotlin-Coroutines (don’t know what’s this, read here)
  • Comfortable with Classes and Objects in Kotlin

Now, let’s get start the code

Create a new android project

  • Go to File>New>New Project
  • Select Empty Activity and click Next
  • Give your project a suitable name and enter package name (or leave it as default)
  • Select Kotlin as Language and choose Minimum SDK (you can get help from Help me choose)
  • Click Finish
  • After some processing time, the Android Studio main window will appear (make sure you have active internet connection)

Add dependencies

Open build.gradle (app level) file

and add this in dependencies<>

Note: Make sure that id ‘kotlin-kapt’ is added in plugins<> or you will get a gradle exception while syncing the project.

Create a Model or Entity

It is the table for the database having Entity annotation. Room creates a separate table for each class that has entity annotation with field of the class as columns of the table. So, must create a Primary Key and give a name to the table.

Читайте также:  Взаимодействие между фрагментами android

Follow the steps

  • Create a new data class FoodItem
  • Annotate with @Entity with table name before class definition
  • Create fields name and price
  • Make nameprimary key and give both fields suitable column name

Code for the entity class :

Note: Make sure that when you use this entity then for every object you create, give unique string to the Name otherwise the new data will override the old data as name is the primary key of the table.

Create DAO (Data Access Object)

Here, we are going to associate SQL queries with the function calls like

  • Getting all food items alphabetically
  • Add new food item
  • Delete a food item

Follow these steps to create DAO

  • Create a kotlin interface FoodItemDao
  • Annotate with @Dao
  • Create functions for above tasks in the Dao interface

Code for the DAO:

  • Flow<> from kotlin-coroutines is used to observe data changes in the database. Using a return value of type Flow in the method description, Room generates all necessary code to update the Flow when the database is updated. When Room queries return Flow, the queries are automatically run asynchronously on a background thread.
  • suspend fun are generally used to handle long running tasks without blocking the main thread. Learn more about suspend function here
  • @Insert and @Delete are DAO method annotations where SQL query is not required but there is no annotation to get a list of items so we have to add query manually for this using @Query
  • OnConflictStrategy.IGNORE ignores the conflict when adding new item if the item is already present in the table.

Implement the Room Database

Room is a database layer on top of an SQLite database. Room uses the DAO to issue queries to its database.

Create an abstract class FoodItemRoom and extent it with RoomDatabase() and add this code to the class:

version and exportSchema are mainly used when we have to make Database Migrations, that’s why exportSchema is set to false here.

In case you want to learn more about Migrations

Create Repository

The repository class is responsible for interacting with the Room database and will need to provide methods that use the DAO to insert, delete and query items.

  • Create a kotlin class FoodItemRepository
  • Pass FoodItemDao as an argument
  • Add this code in the class

In insert() and delete() functions we are directly inserting and deleting food item without ensuring that long running tasks shouldn’t perform on the main thread because room by default runs suspend queries off the MainThread and we are not required anything else to implement.

Implement ViewModel

The ViewModel is responsible to provide data to the UI and survive configuration changes such as screen rotations. Learn more about view model

  • Create a kotlin class FoodItemViewModel and extend with ViewModel()
  • Now add this code
  • To launch a new coroutine ViewModels have a coroutine scope based on their lifecycle called viewModelScope , is used here.
  • Created the ViewModel and implemented a ViewModelProvider.Factory that gets as a parameter the dependencies needed to create FoodItemViewModel : the FoodItemRepository

Instantiate Repository and Database

To have only one instance of the database and of the repository in the entire application create them as members of the Application class.

  • Create a new class MyApplication that extends Application
  • Here’s the code for the application class

Note: Do not forget to update AndroidManifest.xml , set MyApplication as application android:name

All done with the implementation of Room. Now only thing remaining is connection of data with the UI.

Manage Data in Activity

  • Open MainActivity.kt and create viewModel before onCreate() function of the activity

Now you can call the functions we have created in FoodItemViewModel like get all food items, add new item, delete an item.

In onCreate() function of the activity add this code

  • Add New Item and Delete old Item

When you want to add new item or to delete an existing item then use foodItemViewModel to access all the functions.

Tip: After adding or deleting items from the database you don’t need to update the UI because viewModel observe the data changes in the database and by default execute observer foodItemViewModel.allFoodItems.observe() and whatever task you have perform in the observe() , room will execute that task automatically.

Isn’t it just wow…

Showing Data from Database

This is just a demo to test that data is saved in room database or not.

This code should be in onCreate() method of MainActivity.kt after setContentView()

Tip: If the foodItemList returned by the foodItemViewModel is null, this means that no data is present in Room and you have to first insert items in the database.

After running the app this dialog appears

According to the query we write in DAO class for getting all the food items, the list of food items is sorted alphabetically.

Summing up…

This post has demonstrated how to use Room Persistence Library to store data in a local database.

If you want a deep dive in Room Database then you should refer this Codelab

Источник

Оцените статью