Exercise 11 - ShoppingList with a Room
Project name : E11 Room Shopping List
Introduction
This exercise teaches you how to save data in a local database using a Room. Room provides an abstraction layer over SQLite to allow fluent database access while harnessing the full power of SQLite.
Read carefully Room introduction from the Android developer site: Room overview. Get familiar with Database, Entity and DAO.
Example video:
Create a new Android application project
Launch Android Studio and create a new project with default settings.
- Select Empty Activity template
- Give unique application name E11 Room Shopping List
- Use your own company domain name in package name (for example example.com)
- Click Finish
Add Room libraries
You need to add Room libraries to build.gradle (Module: App) file in your project. Remember check the latest stable Room version) and use that one in in your build.gradle.
Basicly you will need to modify your project gradle.build file.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Create a layout files
You will need layout files for the MainActivity, which will hold a RecyclerView. RecyclerView need a layout file to display each shopping list item. And finally one layout file for the custom dialog to ask a new shopping list item. These will be covered next.
Layout for the main activity
First delete Template generated "Hello World" TextView from your layout and add Recycler View to your main layout. Remember give a recyclerView
id for your RecyclerView.
Then create a new Vector Asset and use it in the FloatingActionButton. Select your project app folder with right mouse button and select: new > Vector Asset. Click a “android robot” and search “add” asset. Use white color.
Add Float Action Button to your activity_main.xml file and use created drawable in FloatingActionButton.
RecyclerView's layout item
Add a new layout file and name it to recyclerview_item.xml. This layout will be used inside a RecyclerView component. Use horizontal LinearLayout to hold three TextViews. Give the following id’s to TextViews: nameTextView
, countTextView
and priceTextView
.
Click image to see it bigger!
Tip
You can add sample text to your strings.xml resources and use those text in your TextView
elements to see that your layout works correctly. Remember set your layout height to wrap_content
or your one item will take a whole screen space: android:layout_height="wrap_content"
.
Ask a new shoppling list item
Add a new layout file and name it to dialog_ask_new_shopping_list_item.xml. This layout will be used in the custom dialog. Use multiple LinearLayout’s to hold three TextViews and EditTexts. Give the following id’s to EditTexts: nameEditText
, countEditText
and priceEditText
.
Click image to see it bigger!
Room components
ShoppingListItem
Create a new Kotlin file and name it to ShoppingListItem. This file represents a table within the Room database. Table name will be shopping_list_table
, id will be autoGenerate id and other variables describes a shopping list data.
1 2 3 4 5 6 7 8 9 10 11 |
|
ShoppingListDao
Create a new Kotlin file and name it to ShoppingListDao. This file contains methods used for accessing the database. All shopping list items can be queried with getAll()
function. This function will return MutableList
with ShoppingListItems. A new item can be added with insert()
function. This function will return the auto increment id (Long) to the caller application. One item can be deleted with a delete()
function. This function id parameter will be used inside "DELETE FROM"
query.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
ShoppingListRoomDatabase
Create a new Kotlin file and name it to ShoppingListRoomDatabase. This file contains the database holder and serves as the main access point for the underlying connection to your app’s persisted, relational data. Above dao funtions can be called with shoppingListDao()
function.
1 2 3 4 5 6 7 |
|
RecyclerView and Adapter
Get familiar with a RecyclerView and Adapter from course material or here Create a List with RecyclerView from Android Developer site.
ShoppingList Adapter
RecyclerView needs an adapter, which holds the recyclerView’s data and binds it to the UI. Adapter will get the shopping list data using a parameter.
Create a new Kotlin file and name it to ShoppingListAdapter.
1 2 3 4 5 6 7 8 9 |
|
onCreateViewHolder
onCreateViewHolder
function will be called every single time, when a new shopping list item will be displayed in the recycler view.
1 2 3 4 5 6 7 |
|
ViewHolder
This will use ViewHolder
inner class to get access to recyclerview_item layout views.
1 2 3 4 5 6 7 |
|
onBindViewHolder
onBindViewHolder
function will be called to bind data to layout and UI.
1 2 3 4 5 6 7 8 9 |
|
getItemCount
getItemCount
will return item's count in your data.
1 2 |
|
update
An own update
function will be used later when a new data will be updated to adapter.
1 2 3 4 5 |
|
Use a RecyclerView to display ShoppingList items
Created ShoppingListAdapter
need to be used inside RecyclerView. Modify MainActivity’s onCreate()
function to include adapter and use it in a recyclerView
. A new empty shoppingList instance will be created and passed to the adapter.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
Initialize database and load shopping list items
Database connection
Define a shopping list Room database object inside MainActivity
class.
1 2 |
|
Modify MainActivity’s onCreate()
function to initialize database object after adapter in above code. Here we acquire an instance of database to our code.
1 2 3 4 5 6 7 8 9 |
|
Load all shopping list items from database
Create a loadShoppingListItems()
function below onCreate()
function. A good question is, how we can load data from the database, because it can’t be done in Main UI thread (we can, if allowMainThreadQueries()
is used, when a database connection is created – but it should be avoid). Use a AsyncTask, Handler or maybe own Thread? All of those are a good answers, but… We need to do a different actions (read, delete, update, ...) to the database, how we can handle all of those nicely?
In a real world, an Android Architecture Components should be used. This tutorial will be kept now as simple as it can be. That’s why, own thread will be used with database actions.
A new thread will be created and all the stored shopping list items will be loaded. Message will be send (to UI thread) with a Handler and adapter’s data will be updated line 12.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
Add a new shopping list item
AskShoppingListItemDialogFragment
Create a new Kotlin file and name it to AskShoppingListItemDialogFragment. This fragment will be used to create a custom dialog, which will be used to ask a new shopping list item from the user. If you are not a familiar with a dialogs yet, you should read Dialogs material from the Android Developer site.
Modify code to include class and onCreateDialog()
function, which will be used to create a custom dialog.
1 2 3 4 5 6 |
|
The easiest way to create a dialog is to use AlertDialog.Builder
class. This class allows you to include dialog view, title, message and buttons easily. Function need to return an instance of the created dialog.
Modify the content’s of the onCreateDialog()
as shown in a below. First we load the custom layout for the dialog in line 3. A new dialog will be created inline 6. Dialog’s button event handlers are defined in lines 10 and 19. A new shopping list item will be created, when “Ok” button is pressed. Dialog will only closed now. A new shopping list item will not be send/saved to database yet. This will be corrected soon.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
Sending a new shopping list item to mainactivity
Now dialog is working as a fragment inside a MainActivity. You will need to define an interface with a method for each type of click event in dialog (now we are only defining a positivebutton == ok). Then, implement that interface in the host component, which will receive the action events from the dialog.
Create AddDialogListener
interface inside AskShoppingListItemDialogFragment
and define onDialogPositiveClick
function inside it. This function need to be inside a MainActivity
, if it is using this interface. This is how we can pass the data from dialog to main activity.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
Modify dialog class to call above interface method, before dialog closes in setPositiveButton.
1 2 3 4 5 6 7 8 9 |
|
Modify MainActivity to use above interface
Now above dialog will call host’s onDialogPositiveClick
function, if host is using that interface. Modify MainActivity to use above interface.
1 2 3 4 5 6 |
|
And create onDialogPositiveClick
inside it. Here you will get the new shopping list item from the dialog. A new thread will be created and new item will be inserted to the database. Insert function will be used and it returns autoincrement id used with a new item in database. It will be used inside the item used in the UI. So, the correct item can be later deleted with a swipe.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
Add a new item
Use a floating action button to create and open a new custom dialog. Add FAB code in onCreate()
function to open a custom dialog.
1 2 3 4 5 6 |
|
Delete a shopping list item with a swipe
A final step in this exercise is to delete a row from the recyclerView (also in adapter and db). Add a initSwipe()
function call at the last line in the onCreate()
function and create a following function inside MainActivity.
Here ItemTouchHelper
will be used to determine LEFT
swipe in line 4. You need to define onSwiped()
and onMoved()
functions. Now only onSwiped
function is used for a deleting. RecyclerViews holder position will be used to remove shopping list item from UI and from the database. Own made thread will be used with item deletion. After deletion is ready, Hander object will be used to show a message to end user and notify data change in the adapter.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
|
Run and test your application
Run your application. Now it should save shopping list items to local database.
Test and push
Test your application in emulator, take screenshots and commit/push your project and screenshots back to JAMKIT/GitLab. Remember move your exercise/issue ticket from Doing to In Review in Issues Board and write your learning comments to issue comments.