1 00:00:00,000 --> 00:00:00,300 2 00:00:00,300 --> 00:00:02,133 TOMMY MACWILLIAM: In this video, we're going 3 00:00:02,133 --> 00:00:06,870 to take a look at how to save data to the user's device from your app. 4 00:00:06,870 --> 00:00:08,910 And to do that, we're going to be building 5 00:00:08,910 --> 00:00:11,410 an app that lets you take notes. 6 00:00:11,410 --> 00:00:14,460 So you'll be able to browse a list of notes that you've taken, 7 00:00:14,460 --> 00:00:18,990 create new notes, type something out, and then persist that, or save it, 8 00:00:18,990 --> 00:00:20,650 to the user's phone. 9 00:00:20,650 --> 00:00:24,540 So if they quit your app and reopen it, they can have all of their data still 10 00:00:24,540 --> 00:00:25,540 there. 11 00:00:25,540 --> 00:00:27,000 So let's get started. 12 00:00:27,000 --> 00:00:29,670 To persist data to the user's device, we're 13 00:00:29,670 --> 00:00:32,420 going to use something called SQLite. 14 00:00:32,420 --> 00:00:35,760 So SQLite is a really simple database that 15 00:00:35,760 --> 00:00:41,290 works by saving everything into a file with a special format. 16 00:00:41,290 --> 00:00:45,720 And then from that file, you can run SQL queries on it, 17 00:00:45,720 --> 00:00:48,880 just like you could on any other database. 18 00:00:48,880 --> 00:00:52,740 So to start, let's quickly take a look at a few of the different types 19 00:00:52,740 --> 00:00:55,350 of queries that you might write. 20 00:00:55,350 --> 00:00:58,320 The first one is a create query. 21 00:00:58,320 --> 00:01:03,700 So a create query is used to create a new table in the database. 22 00:01:03,700 --> 00:01:05,820 So when you write a create query, you're going 23 00:01:05,820 --> 00:01:09,040 to specify the name of the database you're creating, 24 00:01:09,040 --> 00:01:13,110 the columns in that database, and the types of each column. 25 00:01:13,110 --> 00:01:16,530 So here's an example of a SQLite create statement. 26 00:01:16,530 --> 00:01:20,040 We're going to start by saying create table. 27 00:01:20,040 --> 00:01:22,260 Then we're going to say if not exists. 28 00:01:22,260 --> 00:01:24,750 And that just means, if there's already a table 29 00:01:24,750 --> 00:01:28,110 there called users, just don't bother executing this, 30 00:01:28,110 --> 00:01:29,940 because we're already done. 31 00:01:29,940 --> 00:01:32,970 Then the name of the table so, users. 32 00:01:32,970 --> 00:01:37,290 And then in these parentheses are the names of the columns. 33 00:01:37,290 --> 00:01:41,190 So we have one column here called id INTEGER, 34 00:01:41,190 --> 00:01:45,030 so that means that the name of the column is id, the type is INTEGER. 35 00:01:45,030 --> 00:01:48,840 It's our PRIMARY KEY, so that means it's the unique thing that 36 00:01:48,840 --> 00:01:51,300 identifies each of our rows. 37 00:01:51,300 --> 00:01:53,250 And it's AUTOINCREMENT. 38 00:01:53,250 --> 00:01:57,630 So that just means that every time a new row is inserted into the table, 39 00:01:57,630 --> 00:02:01,870 we're going to take the id of the most recent row and add 1 to that. 40 00:02:01,870 --> 00:02:06,540 So this will basically be sequential as you're adding rows to the database. 41 00:02:06,540 --> 00:02:09,330 Our other column is a text column. 42 00:02:09,330 --> 00:02:12,510 It's called name and because its type is TEXT, 43 00:02:12,510 --> 00:02:17,460 it allows you to insert any arbitrary length text and store that as a string. 44 00:02:17,460 --> 00:02:22,200 After you've created a table, you might want to run an insert query. 45 00:02:22,200 --> 00:02:28,110 So INSERT, as its name suggests, is going to add rows to a database table. 46 00:02:28,110 --> 00:02:32,370 To write an insert query, we're going to say INSERT INTO, followed 47 00:02:32,370 --> 00:02:36,120 by the name of our table, which is users, and then 48 00:02:36,120 --> 00:02:41,760 in parentheses, the names of the columns that you want to specify values for. 49 00:02:41,760 --> 00:02:46,360 So in this table, we just had one column called name, so we'll have that. 50 00:02:46,360 --> 00:02:48,450 Then we have the word VALUES. 51 00:02:48,450 --> 00:02:51,870 And then, again, a comma separated list of all of the values 52 00:02:51,870 --> 00:02:54,060 that we'd like to insert. 53 00:02:54,060 --> 00:02:58,140 So here we're inserting a single value of Tommy. 54 00:02:58,140 --> 00:03:03,280 After we've inserted rows, we might want to read them back from the database. 55 00:03:03,280 --> 00:03:07,200 So to do that, we're going to use a select query. 56 00:03:07,200 --> 00:03:12,330 So we can say SELECT *, which means select all of the columns 57 00:03:12,330 --> 00:03:13,560 from the table. 58 00:03:13,560 --> 00:03:17,070 If we wanted to, we also could have given a comma separated list 59 00:03:17,070 --> 00:03:19,320 of columns we wanted to read. 60 00:03:19,320 --> 00:03:22,090 Then we'll say FROM and the name of the table. 61 00:03:22,090 --> 00:03:25,020 So here the name of our table is users. 62 00:03:25,020 --> 00:03:29,620 And then we'll have a WHERE clause to filter down the rows. 63 00:03:29,620 --> 00:03:33,930 So we only want to select those rows where the name column is 64 00:03:33,930 --> 00:03:36,630 exactly equal to the string Tommy. 65 00:03:36,630 --> 00:03:38,910 And so if we just have that one row in our database, 66 00:03:38,910 --> 00:03:40,900 this will return us that one row. 67 00:03:40,900 --> 00:03:45,720 If there are multiple rows with the name of Tommy, it will return multiple rows. 68 00:03:45,720 --> 00:03:49,830 We also might want to update rows in our database. 69 00:03:49,830 --> 00:03:53,640 So we could say UPDATE followed by the name of that table. 70 00:03:53,640 --> 00:03:56,770 We could say SET name = value. 71 00:03:56,770 --> 00:03:58,680 So we're going to set the name column. 72 00:03:58,680 --> 00:04:01,530 We're going to use the value of Tommy M. And then 73 00:04:01,530 --> 00:04:05,670 we'll have another WHERE clause to filter down the rows we want to update, 74 00:04:05,670 --> 00:04:10,290 so we can say where the name column is equal to Tommy. 75 00:04:10,290 --> 00:04:12,480 So again this is not going to update all rows. 76 00:04:12,480 --> 00:04:16,633 It'll just update the rows where clause applies. 77 00:04:16,633 --> 00:04:17,800 So let's jump right into it. 78 00:04:17,800 --> 00:04:20,670 Now that we have some basics SQL queries ready to go, 79 00:04:20,670 --> 00:04:23,800 let's learn how we can use them in our app. 80 00:04:23,800 --> 00:04:25,950 So let's open up Android Studio. 81 00:04:25,950 --> 00:04:30,388 And just like we do every time, let's start a new Android Studio project, 82 00:04:30,388 --> 00:04:33,180 select empty activity, because we're going to be writing everything 83 00:04:33,180 --> 00:04:35,970 ourselves, click Next. 84 00:04:35,970 --> 00:04:39,120 And the name of our application, we'll be a little less clever this time 85 00:04:39,120 --> 00:04:41,440 and just call it notes. 86 00:04:41,440 --> 00:04:44,110 Remember package name is just whatever you want. 87 00:04:44,110 --> 00:04:46,720 We're using the CS50 domain backwards. 88 00:04:46,720 --> 00:04:48,900 Save location, wherever you want. 89 00:04:48,900 --> 00:04:51,000 Make sure language is Java. 90 00:04:51,000 --> 00:04:52,770 Choose your minimum API level. 91 00:04:52,770 --> 00:04:55,960 And make sure use AndroidX is checked. 92 00:04:55,960 --> 00:04:58,547 And now click Finish. 93 00:04:58,547 --> 00:05:00,630 All right, we've seen this a few times before now. 94 00:05:00,630 --> 00:05:03,000 We know the code that's generated. 95 00:05:03,000 --> 00:05:04,670 Move this over. 96 00:05:04,670 --> 00:05:08,430 And so now, as we did last time, let's start with the views. 97 00:05:08,430 --> 00:05:11,520 Let's sketch out the views that our app is going to have. 98 00:05:11,520 --> 00:05:14,340 Then let's take care of any necessary models. 99 00:05:14,340 --> 00:05:18,000 And then let's write the controller that wires everything up. 100 00:05:18,000 --> 00:05:22,560 So our app is going to have two screens, or two activities. 101 00:05:22,560 --> 00:05:25,440 The first one is going to be a list of all 102 00:05:25,440 --> 00:05:27,840 the notes the user has on their device. 103 00:05:27,840 --> 00:05:31,560 And the second one is going to be a screen that lets you edit a note 104 00:05:31,560 --> 00:05:34,060 and save it back to a database. 105 00:05:34,060 --> 00:05:36,810 So let's write that first activity first. 106 00:05:36,810 --> 00:05:41,590 Because it's a list of notes, that says we should probably use a RecyclerView. 107 00:05:41,590 --> 00:05:43,030 So let's do that. 108 00:05:43,030 --> 00:05:46,770 Let's open up our main activity XML. 109 00:05:46,770 --> 00:05:51,530 And just like we did last time, we're going to add a RecyclerView. 110 00:05:51,530 --> 00:05:53,510 But before we can do that, remember we have 111 00:05:53,510 --> 00:05:56,250 to add RecyclerView to our project. 112 00:05:56,250 --> 00:06:01,020 So let's open up build.gradle. 113 00:06:01,020 --> 00:06:03,090 Add as our implementation. 114 00:06:03,090 --> 00:06:07,310 We had androidx.recyclerview. 115 00:06:07,310 --> 00:06:10,880 Name is recyclerview. 116 00:06:10,880 --> 00:06:14,300 And the version was 1.0.0. 117 00:06:14,300 --> 00:06:15,980 And we'll sync this. 118 00:06:15,980 --> 00:06:18,630 So it looks like our sync was successful, 119 00:06:18,630 --> 00:06:22,410 so now we can use a RecyclerView in our layout. 120 00:06:22,410 --> 00:06:24,130 So let's come back here. 121 00:06:24,130 --> 00:06:28,010 And just like we did last time, let's replace this text view 122 00:06:28,010 --> 00:06:30,290 with a RecyclerView. 123 00:06:30,290 --> 00:06:32,160 So we can say androidx. 124 00:06:32,160 --> 00:06:34,550 RecyclerView is going to autocomplete for us. 125 00:06:34,550 --> 00:06:38,110 We can say match_parent, again, just like that. 126 00:06:38,110 --> 00:06:42,600 And now, just like before, we have this full screen RecyclerView. 127 00:06:42,600 --> 00:06:46,370 So now we've added a RecyclerView to our layout. 128 00:06:46,370 --> 00:06:48,860 Next, we want to create an adapter. 129 00:06:48,860 --> 00:06:50,990 Just like we did last time, the adapter was 130 00:06:50,990 --> 00:06:55,040 used to manage the data that's displayed in RecyclerView 131 00:06:55,040 --> 00:06:58,650 and define how that data could be displayed. 132 00:06:58,650 --> 00:07:00,260 So let's create a new class. 133 00:07:00,260 --> 00:07:03,280 134 00:07:03,280 --> 00:07:06,430 We'll call it NotesAdapter. 135 00:07:06,430 --> 00:07:09,460 No need to specify anything for now. 136 00:07:09,460 --> 00:07:11,930 And we've created a new class. 137 00:07:11,930 --> 00:07:15,180 The other thing we need to do is create a new layout. 138 00:07:15,180 --> 00:07:19,330 And the layout is going to define what each row looks like. 139 00:07:19,330 --> 00:07:23,230 So we can actually use a layout that was pretty much identical to the last one, 140 00:07:23,230 --> 00:07:26,380 so we'll call this our note_row. 141 00:07:26,380 --> 00:07:29,750 142 00:07:29,750 --> 00:07:30,590 Tap OK. 143 00:07:30,590 --> 00:07:32,840 Come over here to text. 144 00:07:32,840 --> 00:07:35,030 And let's just do exactly what we did last time. 145 00:07:35,030 --> 00:07:38,420 The first thing we did was we added an ID. 146 00:07:38,420 --> 00:07:42,860 And we called this our note_row. 147 00:07:42,860 --> 00:07:45,140 And then we added a text view. 148 00:07:45,140 --> 00:07:51,410 Again, we had match_parent on the width and wrap_content on the height. 149 00:07:51,410 --> 00:07:54,890 And then we gave it an ID so that we could access it later. 150 00:07:54,890 --> 00:07:59,750 And let's just call this note_row_text. 151 00:07:59,750 --> 00:08:00,400 And that's it. 152 00:08:00,400 --> 00:08:02,170 Hopefully, all this looks really familiar. 153 00:08:02,170 --> 00:08:05,410 It's pretty similar to what we did last time. 154 00:08:05,410 --> 00:08:08,740 Now let's open up our NoteAdapter class. 155 00:08:08,740 --> 00:08:12,670 And we want to extend our RecyclerView.Adapter. 156 00:08:12,670 --> 00:08:15,558 157 00:08:15,558 --> 00:08:18,600 And then for the type, we're going to create a new class in just a minute 158 00:08:18,600 --> 00:08:21,510 called NotesAdapter.NoteViewHolder. 159 00:08:21,510 --> 00:08:27,870 160 00:08:27,870 --> 00:08:29,730 All right, so let's create that class. 161 00:08:29,730 --> 00:08:34,169 public static class NoteViewHolder. 162 00:08:34,169 --> 00:08:40,890 And just like last time, we're going to extend the RecyclerView holder. 163 00:08:40,890 --> 00:08:42,920 We're going to give this a constructor. 164 00:08:42,920 --> 00:08:45,580 We're going to say NoteViewHolder. 165 00:08:45,580 --> 00:08:51,660 Constructor is going to take some generic view, call that view. 166 00:08:51,660 --> 00:08:54,750 And then, just like before, let's add in those fields 167 00:08:54,750 --> 00:08:57,180 for our container and our text view. 168 00:08:57,180 --> 00:09:01,320 So we had a linear layout to represent our container view. 169 00:09:01,320 --> 00:09:02,680 And a text view-- 170 00:09:02,680 --> 00:09:03,540 whoops. 171 00:09:03,540 --> 00:09:08,170 A text view that represented our text view. 172 00:09:08,170 --> 00:09:11,040 We'll call super on the constructor to make sure that we 173 00:09:11,040 --> 00:09:14,130 use that super classes constructor. 174 00:09:14,130 --> 00:09:17,440 And then we'll save references to container view, 175 00:09:17,440 --> 00:09:21,060 so that's going to be view.findViewById. 176 00:09:21,060 --> 00:09:23,310 We had an id of note_row. 177 00:09:23,310 --> 00:09:27,416 And our text view was view.findById(note_row_text). 178 00:09:27,416 --> 00:09:32,430 179 00:09:32,430 --> 00:09:34,260 So that's it for our view holder. 180 00:09:34,260 --> 00:09:38,510 And now remember there are three methods that we have to implement. 181 00:09:38,510 --> 00:09:43,070 We have to implement binding a view holder, creating a view holder, 182 00:09:43,070 --> 00:09:46,410 and getting the number of items in the list. 183 00:09:46,410 --> 00:09:49,790 So first, let's handle creating views. 184 00:09:49,790 --> 00:09:53,090 So we'll have onCreateViewHolder. 185 00:09:53,090 --> 00:09:56,870 Let autocomplete do a bunch of stuff here. 186 00:09:56,870 --> 00:10:07,060 And just like before, we're going to say our LayoutInflator.from 187 00:10:07,060 --> 00:10:09,400 that context object. 188 00:10:09,400 --> 00:10:11,800 Then we're going to call inflate and we're 189 00:10:11,800 --> 00:10:15,280 going to pass in that layout, R.layout. 190 00:10:15,280 --> 00:10:18,130 This time we called it note_row. 191 00:10:18,130 --> 00:10:19,730 It needs a parent. 192 00:10:19,730 --> 00:10:22,150 And we don't need to worry about this other behavior, 193 00:10:22,150 --> 00:10:24,860 so we'll just pass false. 194 00:10:24,860 --> 00:10:26,530 And now, we can just return that. 195 00:10:26,530 --> 00:10:31,990 So we're going to return our NoteViewHolder on that view. 196 00:10:31,990 --> 00:10:35,070 So that's the view that it's going to hold. 197 00:10:35,070 --> 00:10:38,160 So now we need to think about our data. 198 00:10:38,160 --> 00:10:41,640 The next two methods we need to implement are binding the view holder 199 00:10:41,640 --> 00:10:43,720 and getting the number of items. 200 00:10:43,720 --> 00:10:47,490 So it's a good time to think now about our model. 201 00:10:47,490 --> 00:10:50,310 So just like last time, we know that we want 202 00:10:50,310 --> 00:10:54,060 to create a model that represents a note. 203 00:10:54,060 --> 00:10:58,210 And each note will probably have some unique id that makes sense. 204 00:10:58,210 --> 00:11:01,590 And then the contents of a note can just be a string, 205 00:11:01,590 --> 00:11:04,140 since those can be arbitrarily long. 206 00:11:04,140 --> 00:11:07,620 So let's create a model for our note. 207 00:11:07,620 --> 00:11:11,670 But this time, we're not just going to create a regular Java object, 208 00:11:11,670 --> 00:11:15,330 we're going to take advantage of Android's SQLite library. 209 00:11:15,330 --> 00:11:18,840 So first, let's take a look at the documentation for that. 210 00:11:18,840 --> 00:11:22,710 Android's library for persistence is called Room. 211 00:11:22,710 --> 00:11:25,440 And it has a nice guide here on how to use it. 212 00:11:25,440 --> 00:11:27,350 So you can feel free to read through this 213 00:11:27,350 --> 00:11:29,740 and we're going to walk through it together. 214 00:11:29,740 --> 00:11:32,070 So the first thing we need to do is add Room 215 00:11:32,070 --> 00:11:38,620 to our project, which, as you probably guessed, is just using a Gradle file. 216 00:11:38,620 --> 00:11:40,980 So let's just copy these two things here. 217 00:11:40,980 --> 00:11:45,490 Again, you want these two lines to load in everything. 218 00:11:45,490 --> 00:11:49,920 So we'll jump back to our Gradle file, paste these in. 219 00:11:49,920 --> 00:11:51,980 So for a Room version here, I'm just going 220 00:11:51,980 --> 00:11:57,090 to use the latest stable version, which is 2.1.0, 221 00:11:57,090 --> 00:12:00,960 just got that number from looking at the documentation. 222 00:12:00,960 --> 00:12:05,190 You'll notice here that instead of implementation, this second line 223 00:12:05,190 --> 00:12:07,710 says annotation processor. 224 00:12:07,710 --> 00:12:10,110 What's going to happen is we're going to use something 225 00:12:10,110 --> 00:12:14,610 called Java annotations, which is just like that app override thing 226 00:12:14,610 --> 00:12:18,120 that we added before, that annotation before a method. 227 00:12:18,120 --> 00:12:24,220 Now these annotations are going to be used to map fields in some Java object 228 00:12:24,220 --> 00:12:27,240 to columns in a SQLite database. 229 00:12:27,240 --> 00:12:30,270 So basically, to get access to those annotations 230 00:12:30,270 --> 00:12:34,770 and to make sure the compiler can use those annotations to generate code, 231 00:12:34,770 --> 00:12:37,470 we just need to add in this annotation processor. 232 00:12:37,470 --> 00:12:40,350 But I didn't really need to do anything fancy there. 233 00:12:40,350 --> 00:12:43,920 I just copied that right from the documentation. 234 00:12:43,920 --> 00:12:47,400 So let's sync our Gradle project. 235 00:12:47,400 --> 00:12:50,680 Everything looks good there, so we're good to go. 236 00:12:50,680 --> 00:12:54,120 So let's start by creating a new model class. 237 00:12:54,120 --> 00:12:56,370 So we'll say new Java class. 238 00:12:56,370 --> 00:12:59,350 We'll call this Note. 239 00:12:59,350 --> 00:13:01,070 And press OK. 240 00:13:01,070 --> 00:13:06,790 Now here is what we're going to do a bunch of magic using the Room library. 241 00:13:06,790 --> 00:13:10,900 So let's define two fields on this Note class. 242 00:13:10,900 --> 00:13:13,480 Let's call one id. 243 00:13:13,480 --> 00:13:14,650 And that's just an integer. 244 00:13:14,650 --> 00:13:22,630 And let's call the other one contents, to be the contents of the note. 245 00:13:22,630 --> 00:13:25,570 So now we're going to add a few annotations 246 00:13:25,570 --> 00:13:29,050 provided to us from that Room library. 247 00:13:29,050 --> 00:13:35,760 So for this first field, we're going to add the annotation PrimaryKey. 248 00:13:35,760 --> 00:13:39,050 You can see this was imported by this Room library. 249 00:13:39,050 --> 00:13:44,640 And for the second field, we're going to add this annotation called ColumnInfo. 250 00:13:44,640 --> 00:13:49,220 And this specifies that this is another column in our database. 251 00:13:49,220 --> 00:13:52,200 Now annotations can also take arguments. 252 00:13:52,200 --> 00:13:54,602 And so this one takes an argument called name. 253 00:13:54,602 --> 00:13:56,310 And we're just going to name it contents. 254 00:13:56,310 --> 00:13:57,810 It's the same thing. 255 00:13:57,810 --> 00:14:02,190 If you had a column name that was different than this field, 256 00:14:02,190 --> 00:14:05,190 that's where you could specify that mapping. 257 00:14:05,190 --> 00:14:10,620 Now the last annotation we want to add is this entity annotation. 258 00:14:10,620 --> 00:14:16,020 And so this says that this class represents a table in my database 259 00:14:16,020 --> 00:14:21,210 and with its arguments I can specify the name of my table is notes. 260 00:14:21,210 --> 00:14:26,160 So this will create a SQLite table called the notes with two columns, 261 00:14:26,160 --> 00:14:31,080 a primary key integer autoincrement column called id, 262 00:14:31,080 --> 00:14:36,720 and a string column, which corresponds to a text column in SQLite3, 263 00:14:36,720 --> 00:14:39,110 called contents. 264 00:14:39,110 --> 00:14:43,830 And so now, this is really cool, we're just mapping each row in this database 265 00:14:43,830 --> 00:14:46,410 automatically to one of these model objects. 266 00:14:46,410 --> 00:14:49,110 And that's really going to simplify the amount of code 267 00:14:49,110 --> 00:14:53,160 we have to write in order to read and write from this database. 268 00:14:53,160 --> 00:14:55,620 So now that we have our model class done, 269 00:14:55,620 --> 00:14:58,170 let's go ahead and use that in the adapter. 270 00:14:58,170 --> 00:15:04,400 Just like we did last time, let's create a list of note. 271 00:15:04,400 --> 00:15:05,540 We'll call it notes. 272 00:15:05,540 --> 00:15:10,740 And initially, let's just have it be an empty list. 273 00:15:10,740 --> 00:15:15,740 So now we can implement that onBindViewHolder method. 274 00:15:15,740 --> 00:15:21,290 So just like we did before, we can use this position parameter to get a note. 275 00:15:21,290 --> 00:15:26,048 So we'll say Note current is notes.getPosition. 276 00:15:26,048 --> 00:15:28,730 277 00:15:28,730 --> 00:15:32,420 And so now we just want to set the text of this text view 278 00:15:32,420 --> 00:15:34,220 to be the text of the note. 279 00:15:34,220 --> 00:15:37,817 So let's say I have my holder.textView. 280 00:15:37,817 --> 00:15:40,880 281 00:15:40,880 --> 00:15:44,270 And we'll set the text to be current.contents. 282 00:15:44,270 --> 00:15:47,970 283 00:15:47,970 --> 00:15:48,590 Pretty simple. 284 00:15:48,590 --> 00:15:51,440 285 00:15:51,440 --> 00:15:57,020 Lastly, let's define a method to get the number of notes inside of the adapter. 286 00:15:57,020 --> 00:16:00,830 So that's going to be my getItemCount. 287 00:16:00,830 --> 00:16:04,970 And just like before, let's just return notes.size. 288 00:16:04,970 --> 00:16:07,700 289 00:16:07,700 --> 00:16:10,370 OK, so this is a pretty simple version of the adapter. 290 00:16:10,370 --> 00:16:16,260 It doesn't do too much yet, but it's some good boilerplate. 291 00:16:16,260 --> 00:16:17,570 And I have this red line here. 292 00:16:17,570 --> 00:16:19,110 Forgot to say new. 293 00:16:19,110 --> 00:16:21,570 So that's going to fix that compilation error. 294 00:16:21,570 --> 00:16:25,650 So now, just like we did last time, let's add the necessary classes 295 00:16:25,650 --> 00:16:28,870 to our main activity. 296 00:16:28,870 --> 00:16:30,520 So we need a few things. 297 00:16:30,520 --> 00:16:33,880 The first thing we need is a RecyclerView. 298 00:16:33,880 --> 00:16:36,160 And we can just call that RecyclerView. 299 00:16:36,160 --> 00:16:38,950 The next thing we need is an adapter. 300 00:16:38,950 --> 00:16:42,750 So that can be our notes adapter. 301 00:16:42,750 --> 00:16:45,120 And the last thing we need is that layout manager. 302 00:16:45,120 --> 00:16:48,640 303 00:16:48,640 --> 00:16:54,850 Now inside of onCreate, we're going to grab and instantiate these objects. 304 00:16:54,850 --> 00:16:58,180 So RecyclerView is going to be findViewById. 305 00:16:58,180 --> 00:17:01,540 306 00:17:01,540 --> 00:17:05,250 Looks like we forgot to give that an id, so we can come back. 307 00:17:05,250 --> 00:17:07,410 Autocomplete let me know I forgot. 308 00:17:07,410 --> 00:17:15,710 And so I'll just say android: id is RecyclerView. 309 00:17:15,710 --> 00:17:20,260 So now autocomplete should be good and it is. 310 00:17:20,260 --> 00:17:21,609 That's our RecyclerView. 311 00:17:21,609 --> 00:17:26,380 Remember layout manager, we can just say is a linear layout manager. 312 00:17:26,380 --> 00:17:29,380 Give it access to some activity. 313 00:17:29,380 --> 00:17:33,300 And then our notes adapter, it didn't take any arguments in the constructor. 314 00:17:33,300 --> 00:17:39,010 So we can just say new NotesAdapter. 315 00:17:39,010 --> 00:17:41,720 Finally, we can set these values. 316 00:17:41,720 --> 00:17:49,690 So we can say recyclerView.setLayoutManager 317 00:17:49,690 --> 00:17:53,770 and recyclerView.setAdapter. 318 00:17:53,770 --> 00:17:56,050 And so all this should look really familiar. 319 00:17:56,050 --> 00:17:59,060 We're just grabbing that RecyclerView from the layout. 320 00:17:59,060 --> 00:18:02,110 And we're configuring its layout manager, just laying things out 321 00:18:02,110 --> 00:18:03,400 straight in the line. 322 00:18:03,400 --> 00:18:07,060 And we're configuring its adapter, which is a new instance of that adapter 323 00:18:07,060 --> 00:18:08,890 that we just wrote. 324 00:18:08,890 --> 00:18:13,420 So right now, if we were to run this, it wouldn't be a terribly interesting app, 325 00:18:13,420 --> 00:18:17,270 because we know our RecyclerView is going to be empty. 326 00:18:17,270 --> 00:18:21,520 So now, let's go ahead and take care of writing all of the model code 327 00:18:21,520 --> 00:18:24,320 that's necessary to do three things. 328 00:18:24,320 --> 00:18:27,070 The first is creating a new note. 329 00:18:27,070 --> 00:18:31,420 The second is getting all the notes that a user has already created. 330 00:18:31,420 --> 00:18:34,930 And the third is saving a note to disk. 331 00:18:34,930 --> 00:18:39,670 To do that, we're going to write a new class called a DAO, 332 00:18:39,670 --> 00:18:42,790 or it stands for data access object. 333 00:18:42,790 --> 00:18:47,470 And again, we're going to use this Room library that Android provides 334 00:18:47,470 --> 00:18:51,190 to really easily map methods to queries that we're 335 00:18:51,190 --> 00:18:54,320 going to run on the database. 336 00:18:54,320 --> 00:18:55,130 So let's do that. 337 00:18:55,130 --> 00:19:00,020 Let's create a new class to represent our data access object. 338 00:19:00,020 --> 00:19:04,610 So we're going to say a new Java class and we're going to call this a NoteDao. 339 00:19:04,610 --> 00:19:07,910 340 00:19:07,910 --> 00:19:09,570 Click OK. 341 00:19:09,570 --> 00:19:13,010 So if you read through the Room documentation, what you'll find 342 00:19:13,010 --> 00:19:16,850 is the way that this works is we're going to write, not a class, 343 00:19:16,850 --> 00:19:19,110 but actually an interface. 344 00:19:19,110 --> 00:19:21,710 And we're just going to annotate the methods 345 00:19:21,710 --> 00:19:24,620 in this interface with some queries. 346 00:19:24,620 --> 00:19:29,120 And then under the hood, the Room library, while everything is compiling, 347 00:19:29,120 --> 00:19:31,790 is going to generate some classes for us. 348 00:19:31,790 --> 00:19:38,210 So essentially, the compiler is writing some code for us so we don't have to. 349 00:19:38,210 --> 00:19:42,290 So to start, let's change this class to an interface 350 00:19:42,290 --> 00:19:46,220 and add the first annotation, which is a DAO. 351 00:19:46,220 --> 00:19:50,840 So we've specified this is a Room data access object. 352 00:19:50,840 --> 00:19:56,330 And so now the Room library is going to do something with this interface. 353 00:19:56,330 --> 00:20:00,890 First, let's specify a method for creating a note. 354 00:20:00,890 --> 00:20:03,680 Now we don't need to pass any arguments to this method, 355 00:20:03,680 --> 00:20:08,060 because we're just going to create a note with some default values. 356 00:20:08,060 --> 00:20:11,840 So now to specify the SQL query that's going 357 00:20:11,840 --> 00:20:20,240 to be run when you have this create object, we're going to specify @query. 358 00:20:20,240 --> 00:20:24,440 Again, this is another annotation from the Room library. 359 00:20:24,440 --> 00:20:27,320 And here is where we're going to write our SQL. 360 00:20:27,320 --> 00:20:32,310 So we're going to say INSERT INTO notes-- 361 00:20:32,310 --> 00:20:35,000 just need the contents-- 362 00:20:35,000 --> 00:20:40,140 VALUES, we'll just say "new note." 363 00:20:40,140 --> 00:20:43,740 And that's the default value for one of our notes. 364 00:20:43,740 --> 00:20:48,360 So now what's happening here is we're going to generate some code. 365 00:20:48,360 --> 00:20:51,360 And whenever this create method is called, 366 00:20:51,360 --> 00:20:56,150 this SQL query is going to be run on our database. 367 00:20:56,150 --> 00:21:01,880 So let's do the same thing to implement those two other methods. 368 00:21:01,880 --> 00:21:04,300 The next one we can implement is the method 369 00:21:04,300 --> 00:21:07,730 to get all of the notes in the database. 370 00:21:07,730 --> 00:21:12,400 So that's going to return a list of notes. 371 00:21:12,400 --> 00:21:18,150 And we'll call this method getAllNotes. 372 00:21:18,150 --> 00:21:21,280 And again let's use this @Query annotation 373 00:21:21,280 --> 00:21:25,000 to specify the SQL query we want to run. 374 00:21:25,000 --> 00:21:32,100 So we want to say SELECT *, just grab everything, FROM notes. 375 00:21:32,100 --> 00:21:32,830 And that's it. 376 00:21:32,830 --> 00:21:37,270 That's a SQL query that's going to say, give me all of the rows in the database 377 00:21:37,270 --> 00:21:40,540 and grab all of the columns for those rows. 378 00:21:40,540 --> 00:21:42,350 So that was pretty easy. 379 00:21:42,350 --> 00:21:47,710 So last, let's write the method to save notes to our database. 380 00:21:47,710 --> 00:21:51,370 So return type will just be void, because we're not returning anything. 381 00:21:51,370 --> 00:21:53,480 We're just writing something to disk. 382 00:21:53,480 --> 00:21:56,590 And let's call this method save. 383 00:21:56,590 --> 00:22:00,950 Now this method, unlike the other two, requires a couple parameters. 384 00:22:00,950 --> 00:22:03,610 Let's call one contents. 385 00:22:03,610 --> 00:22:05,970 Let's call the other id. 386 00:22:05,970 --> 00:22:09,500 And this makes sense, because in order to save something to the database, 387 00:22:09,500 --> 00:22:13,180 we need to pass in the value to save, then also 388 00:22:13,180 --> 00:22:17,180 the id of the note that we want to save it to. 389 00:22:17,180 --> 00:22:22,150 So we can actually use the values of these parameters inside 390 00:22:22,150 --> 00:22:23,950 of our annotation. 391 00:22:23,950 --> 00:22:27,790 So we'll say @Query and then we'll write our update query. 392 00:22:27,790 --> 00:22:39,730 We're going to say UPDATE notes SET contents = :contents WHERE id = :id. 393 00:22:39,730 --> 00:22:45,140 So this is taking advantage of a SQLite feature called parameter binding. 394 00:22:45,140 --> 00:22:49,180 So this says, wherever I see that :contents, 395 00:22:49,180 --> 00:22:53,740 I'm going to replace that with the value of the variable that's inside of this 396 00:22:53,740 --> 00:22:55,240 method declaration. 397 00:22:55,240 --> 00:22:56,950 And same with id. 398 00:22:56,950 --> 00:23:00,400 So I don't really have to do any kind of fancy string interpolation. 399 00:23:00,400 --> 00:23:05,840 And this is also a much safer way of getting user input into the database. 400 00:23:05,840 --> 00:23:08,110 If you're just manually concatenating strings, 401 00:23:08,110 --> 00:23:11,050 you're opening yourself up to different types of attacks. 402 00:23:11,050 --> 00:23:13,870 And so this is just a really safe way of making sure 403 00:23:13,870 --> 00:23:17,590 that you take some user input, like the contents of a note, 404 00:23:17,590 --> 00:23:21,790 and use it in the context of a SQLite query. 405 00:23:21,790 --> 00:23:22,480 So this is it. 406 00:23:22,480 --> 00:23:26,080 This is actually our entire data access object. 407 00:23:26,080 --> 00:23:28,960 Interestingly, we didn't have to write any lines of code 408 00:23:28,960 --> 00:23:31,720 to manually save something to the database 409 00:23:31,720 --> 00:23:34,210 or open a file or anything like that. 410 00:23:34,210 --> 00:23:37,960 We also didn't need to write any code to convert some kind of row object 411 00:23:37,960 --> 00:23:40,000 to some kind of note object. 412 00:23:40,000 --> 00:23:43,570 All of that is taken care of by this Room library. 413 00:23:43,570 --> 00:23:46,390 What we did have to write, though, was the SQL 414 00:23:46,390 --> 00:23:51,140 that we want to be executed when you call these various methods. 415 00:23:51,140 --> 00:23:54,280 So that's it for our Note DOA. 416 00:23:54,280 --> 00:23:58,630 We have to write one more class in order to use this. 417 00:23:58,630 --> 00:24:02,500 And that class is called a database class. 418 00:24:02,500 --> 00:24:07,000 So just as we did before, let's create a new class. 419 00:24:07,000 --> 00:24:09,235 Let's call this our NoteDatabase. 420 00:24:09,235 --> 00:24:12,120 421 00:24:12,120 --> 00:24:15,080 In here, as you probably guessed, we're going 422 00:24:15,080 --> 00:24:20,710 to use some more annotations provided to us by the Room library. 423 00:24:20,710 --> 00:24:26,860 So the annotation we're going to use for this class is the database annotation. 424 00:24:26,860 --> 00:24:30,280 So the database annotation specifies that this 425 00:24:30,280 --> 00:24:35,590 is the database, or sort of the entry point for all of the data access 426 00:24:35,590 --> 00:24:38,330 objects that your app is going to use. 427 00:24:38,330 --> 00:24:41,560 So we can see here from our autocomplete that this annotation 428 00:24:41,560 --> 00:24:45,010 takes one argument called entities. 429 00:24:45,010 --> 00:24:49,300 And here, we can specify a list of all of the data access objects 430 00:24:49,300 --> 00:24:51,130 that we need to use. 431 00:24:51,130 --> 00:24:54,370 So we just have one, which is our NoteDao, 432 00:24:54,370 --> 00:24:57,430 and we're going to use this .class syntax to indicate that 433 00:24:57,430 --> 00:25:01,930 we're specifying and passing in a class. 434 00:25:01,930 --> 00:25:02,870 Second argument. 435 00:25:02,870 --> 00:25:06,743 So this annotation is a version number. 436 00:25:06,743 --> 00:25:09,910 Let's say you release an app and you're sort of changing the database scheme 437 00:25:09,910 --> 00:25:13,030 and you want to version it, you can just specify a version here 438 00:25:13,030 --> 00:25:17,710 to let Room know when you have a different database schema. 439 00:25:17,710 --> 00:25:19,890 OK, so that looks pretty good. 440 00:25:19,890 --> 00:25:22,160 Now we're saying that inside of this database, 441 00:25:22,160 --> 00:25:28,740 we have this one data access object that we can use to get different values. 442 00:25:28,740 --> 00:25:31,470 So now let's move on to this class. 443 00:25:31,470 --> 00:25:37,560 The first thing we want to do is extend our Room database class. 444 00:25:37,560 --> 00:25:41,900 And so this is a base class that's going to specify a bunch of different methods 445 00:25:41,900 --> 00:25:43,310 for us. 446 00:25:43,310 --> 00:25:49,370 And one other thing we want to do is add this keyword abstract to this class. 447 00:25:49,370 --> 00:25:55,250 So an abstract class is somewhere between a class and an interface. 448 00:25:55,250 --> 00:25:58,670 In an abstract class, you can have some methods 449 00:25:58,670 --> 00:26:02,390 that have bodies and definitions, and you can also 450 00:26:02,390 --> 00:26:05,780 have some methods that don't have any bodies. 451 00:26:05,780 --> 00:26:08,990 And when you extend an abstract class, you 452 00:26:08,990 --> 00:26:13,520 have access to all of those methods that are defined and have a body, 453 00:26:13,520 --> 00:26:17,240 and you're required to implement these other methods that 454 00:26:17,240 --> 00:26:18,895 are marked as abstract. 455 00:26:18,895 --> 00:26:21,020 So you can think about it as sort of a combination. 456 00:26:21,020 --> 00:26:24,710 It's like an interface that requires you to sign this contract 457 00:26:24,710 --> 00:26:28,070 to implement some set of methods, but like a class, 458 00:26:28,070 --> 00:26:34,630 it also has some functionality already so you can call some other classes. 459 00:26:34,630 --> 00:26:38,620 So by saying abstract in front of the method, 460 00:26:38,620 --> 00:26:41,640 that's how you indicate that this isn't something 461 00:26:41,640 --> 00:26:43,850 that I'm going to implant myself. 462 00:26:43,850 --> 00:26:49,570 Instead, this is something that's going to be implemented by somebody else. 463 00:26:49,570 --> 00:26:53,210 So we're going to add one abstract method to this class. 464 00:26:53,210 --> 00:27:01,880 We're going to say public abstract NoteDao and we'll just call it noteDao. 465 00:27:01,880 --> 00:27:04,070 And so the reason that this is abstract is 466 00:27:04,070 --> 00:27:09,410 because, again, this Room library, when you're compiling these files, 467 00:27:09,410 --> 00:27:12,560 it's going to generate some code for us. 468 00:27:12,560 --> 00:27:16,070 And so the class that implements, or extends, 469 00:27:16,070 --> 00:27:20,930 this abstract class is going to be generated by the Room library. 470 00:27:20,930 --> 00:27:24,260 And with this @database annotation, that's 471 00:27:24,260 --> 00:27:27,140 what's going to tell the compiler, lets go and generate 472 00:27:27,140 --> 00:27:29,610 some code that can be used. 473 00:27:29,610 --> 00:27:33,290 So we're not actually going to have to implement any of this ourself. 474 00:27:33,290 --> 00:27:37,410 It's this Room library that's writing the code for us. 475 00:27:37,410 --> 00:27:41,120 So now, that's all of the model code we're going to have to write. 476 00:27:41,120 --> 00:27:44,140 Let's just quickly recap what we did. 477 00:27:44,140 --> 00:27:47,630 First, we defined our note class. 478 00:27:47,630 --> 00:27:51,810 In our note class is where we define what our data looks like. 479 00:27:51,810 --> 00:27:55,470 We said we have a table for notes and each entry 480 00:27:55,470 --> 00:27:58,230 in that table has two fields. 481 00:27:58,230 --> 00:28:01,590 One of it is a unique identifier that's an integer. 482 00:28:01,590 --> 00:28:07,380 And the other is a string that contains some contents about the note. 483 00:28:07,380 --> 00:28:09,720 So this defined our table. 484 00:28:09,720 --> 00:28:12,510 After we defined our table, we defined a way 485 00:28:12,510 --> 00:28:16,260 to access that table and sort of interact with the table. 486 00:28:16,260 --> 00:28:18,660 And we defined three methods to do that. 487 00:28:18,660 --> 00:28:23,520 We defined a method that runs in insert query to add values to the table. 488 00:28:23,520 --> 00:28:28,620 We defined a method that runs a select query to get data back from the table. 489 00:28:28,620 --> 00:28:35,050 And we defined an update method to save data that's inside of the table. 490 00:28:35,050 --> 00:28:39,820 Last, we created this database class that basically collects all 491 00:28:39,820 --> 00:28:42,280 of the data access objects together. 492 00:28:42,280 --> 00:28:47,050 In our case, we only have one and so we listed it here in our annotation. 493 00:28:47,050 --> 00:28:50,740 And then we created one abstract method that someone else 494 00:28:50,740 --> 00:28:55,630 is going to implement for us to get access to an instance of that data 495 00:28:55,630 --> 00:28:57,260 access object. 496 00:28:57,260 --> 00:29:00,400 So now that all of our model code is written, 497 00:29:00,400 --> 00:29:05,180 let's take a look at how we can use that model code in our application. 498 00:29:05,180 --> 00:29:09,460 So first, let's jump back to that main activity. 499 00:29:09,460 --> 00:29:13,090 So first, let's define an object that's going to represent 500 00:29:13,090 --> 00:29:15,740 a connection to this database. 501 00:29:15,740 --> 00:29:19,930 So I'm going to create a new static field on my main activity. 502 00:29:19,930 --> 00:29:22,000 Its type is NotesDatabase. 503 00:29:22,000 --> 00:29:24,730 And I'm going to call it database. 504 00:29:24,730 --> 00:29:28,180 And the reason I'm making this static is because I want all the different 505 00:29:28,180 --> 00:29:31,010 activities in my app-- in this case, there are only two-- 506 00:29:31,010 --> 00:29:34,450 to use the same instance of a database. 507 00:29:34,450 --> 00:29:37,780 And rather than passing that around constructors everywhere, 508 00:29:37,780 --> 00:29:43,280 I can just make this static and then other classes in my app can use it. 509 00:29:43,280 --> 00:29:46,640 So once I've defined the field, let's set its value to something. 510 00:29:46,640 --> 00:29:50,530 So I'm going to say Room.databaseBuilder. 511 00:29:50,530 --> 00:29:53,170 And this takes a couple arguments, it looks like. 512 00:29:53,170 --> 00:29:54,910 The first argument is a context. 513 00:29:54,910 --> 00:30:00,340 And we saw before that there's just some global context object we can use. 514 00:30:00,340 --> 00:30:03,500 The next argument is going to be the class name for our database. 515 00:30:03,500 --> 00:30:07,010 And that's our NotesDatabase.class. 516 00:30:07,010 --> 00:30:09,130 And finally, we want a name. 517 00:30:09,130 --> 00:30:11,590 So that's sort of a string name for our database 518 00:30:11,590 --> 00:30:13,990 and that's the file that we're going to save on disk. 519 00:30:13,990 --> 00:30:17,610 Let's just call that notes. 520 00:30:17,610 --> 00:30:19,650 The next thing we want to do is just allow 521 00:30:19,650 --> 00:30:22,470 our database to run on the foreground. 522 00:30:22,470 --> 00:30:25,710 So normally, you'd want it to sort of do heavy database queries 523 00:30:25,710 --> 00:30:27,160 in some kind of background task. 524 00:30:27,160 --> 00:30:28,660 We're not going to worry about that. 525 00:30:28,660 --> 00:30:33,640 So let's just, say, allow this to happen on this sort of main foreground task. 526 00:30:33,640 --> 00:30:36,150 And finally, we're going to call build. 527 00:30:36,150 --> 00:30:41,690 And so this is going to give us back a database that we can use. 528 00:30:41,690 --> 00:30:43,750 So let's use this new object. 529 00:30:43,750 --> 00:30:48,080 Let's jump over to our NotesAdapter. 530 00:30:48,080 --> 00:30:51,260 And let's create a new method on this adapter 531 00:30:51,260 --> 00:30:54,540 to load everything from the database. 532 00:30:54,540 --> 00:30:57,170 So we'll just call this reload. 533 00:30:57,170 --> 00:31:00,470 So inside of our reload method, let's first set 534 00:31:00,470 --> 00:31:02,980 the value of that notes field. 535 00:31:02,980 --> 00:31:06,360 And so we can say MainActivity.database. 536 00:31:06,360 --> 00:31:09,290 Remember, we made database a static field, 537 00:31:09,290 --> 00:31:15,050 which means that we can access it by referencing this MainActivity class. 538 00:31:15,050 --> 00:31:20,570 So say MainActivity.database dot note data access object, or noteDao, 539 00:31:20,570 --> 00:31:23,300 and that's a method that we defined. 540 00:31:23,300 --> 00:31:26,240 And then we can say, getAllNotes. 541 00:31:26,240 --> 00:31:29,840 And this is going to call that method from the NoteDao, 542 00:31:29,840 --> 00:31:34,910 run that select query, and give us back a list of notes. 543 00:31:34,910 --> 00:31:39,740 Now just like last time, we have to call notifiyDataSetChanged. 544 00:31:39,740 --> 00:31:41,660 And that's going to tell the RecyclerView 545 00:31:41,660 --> 00:31:46,380 that we've just updated that underlying object, reload yourself. 546 00:31:46,380 --> 00:31:49,620 So now that we've written this method, let's use it. 547 00:31:49,620 --> 00:31:54,750 Let's come back to our onCreate and call adapter.reload. 548 00:31:54,750 --> 00:31:57,530 And this says, when the app runs, the first thing it's going to do 549 00:31:57,530 --> 00:32:01,690 is go to the database, grab everything, and display it in the RecyclerView. 550 00:32:01,690 --> 00:32:02,760 View. 551 00:32:02,760 --> 00:32:07,020 So now we have a mechanism for reading notes from the database, 552 00:32:07,020 --> 00:32:09,860 but we don't have a way to create new notes. 553 00:32:09,860 --> 00:32:14,090 And if you remember our UI doesn't have any controls or buttons 554 00:32:14,090 --> 00:32:15,630 to do that either. 555 00:32:15,630 --> 00:32:19,520 So let's add a button to this activity that, when we press it, 556 00:32:19,520 --> 00:32:22,680 is going to create a new note. 557 00:32:22,680 --> 00:32:25,340 And the class that I'm going to use is this class 558 00:32:25,340 --> 00:32:29,360 that's given to us by Android called a floating action button. 559 00:32:29,360 --> 00:32:31,130 This is a pretty common Android pattern. 560 00:32:31,130 --> 00:32:34,670 You've often seen, you know, a button sort of on top of a list 561 00:32:34,670 --> 00:32:37,670 and you can tap that button and something happens. 562 00:32:37,670 --> 00:32:41,600 So that button is defined in, again, a separate library 563 00:32:41,600 --> 00:32:45,020 that we need to pull in, so let's do that. 564 00:32:45,020 --> 00:32:49,780 And the name of this library is com.google.android.material. 565 00:32:49,780 --> 00:32:54,290 566 00:32:54,290 --> 00:32:59,480 So the name of the library is Material and the version is 1.0.0. 567 00:32:59,480 --> 00:33:02,880 So this is just another class it's provided to us by Android. 568 00:33:02,880 --> 00:33:06,560 And it contains a bunch of other UI elements we might want to use 569 00:33:06,560 --> 00:33:10,510 and so let's just pull those into our project. 570 00:33:10,510 --> 00:33:14,400 So now that we've downloaded this library of material UI components, 571 00:33:14,400 --> 00:33:16,660 let's use them in our app. 572 00:33:16,660 --> 00:33:21,220 So let's jump back to the layout for our main activity. 573 00:33:21,220 --> 00:33:25,742 So the first thing we want to do is change the layout that's used here. 574 00:33:25,742 --> 00:33:27,450 And we want to pick a layout that's going 575 00:33:27,450 --> 00:33:30,540 to enable that floating action button to sort of float 576 00:33:30,540 --> 00:33:32,700 on top of the RecyclerView. 577 00:33:32,700 --> 00:33:35,490 So we're going to change ConstraintLayout to something else. 578 00:33:35,490 --> 00:33:39,050 We're going to use what's called a CoordinatorLayout. 579 00:33:39,050 --> 00:33:41,550 And this is just basically a different type of layout that's 580 00:33:41,550 --> 00:33:43,990 going to allow us to do what we want. 581 00:33:43,990 --> 00:33:47,640 So after we've changed that, let's come back over to here 582 00:33:47,640 --> 00:33:51,870 and add a floating action button. 583 00:33:51,870 --> 00:33:54,820 584 00:33:54,820 --> 00:34:00,280 So just like before, let's specify a few of those attributes. 585 00:34:00,280 --> 00:34:04,680 So we have our layout width, and let's just have these both be wrap_content. 586 00:34:04,680 --> 00:34:05,580 So that's our width. 587 00:34:05,580 --> 00:34:10,679 588 00:34:10,679 --> 00:34:12,670 That's our height. 589 00:34:12,670 --> 00:34:16,820 Let's give this button an ID, just so we have it. 590 00:34:16,820 --> 00:34:24,040 We have @+id and we have, let's just call this, add_note_button. 591 00:34:24,040 --> 00:34:27,850 After we give it an ID, let's specify where we want it to float. 592 00:34:27,850 --> 00:34:30,739 So let's add our button to the bottom right of the screen, 593 00:34:30,739 --> 00:34:33,190 since that's kind of a common place to put it. 594 00:34:33,190 --> 00:34:39,996 So let's say android: layout_gravity is going to be in the bottom(right). 595 00:34:39,996 --> 00:34:42,730 And then we don't want it to be all the way on the bottom right, 596 00:34:42,730 --> 00:34:45,130 so let's just give it a little bit of padding. 597 00:34:45,130 --> 00:34:47,590 So we'll say android: layout_margin. 598 00:34:47,590 --> 00:34:50,311 599 00:34:50,311 --> 00:34:52,360 And let's just say 16 pixels. 600 00:34:52,360 --> 00:34:54,710 That probably looks pretty good. 601 00:34:54,710 --> 00:34:58,540 So the next thing we want to add is an icon to our button. 602 00:34:58,540 --> 00:35:01,780 And luckily, Android provides a bunch of default icons 603 00:35:01,780 --> 00:35:05,950 that we can use so we don't have to add our own or create our own icon. 604 00:35:05,950 --> 00:35:13,675 To do that, I'm going to use this app: srcCompat 605 00:35:13,675 --> 00:35:16,765 And I'm going to start by saying @android. 606 00:35:16,765 --> 00:35:19,640 And then here, you can see there's a bunch of stuff supplied already. 607 00:35:19,640 --> 00:35:23,330 So if I start typing drawable, I can see a bunch of icons. 608 00:35:23,330 --> 00:35:26,880 So I'm going to use this input_add icon. 609 00:35:26,880 --> 00:35:28,990 And so this is just a little plus. 610 00:35:28,990 --> 00:35:31,850 It basically says this is the system icon 611 00:35:31,850 --> 00:35:35,510 that you should use if you're having a plus button or button that 612 00:35:35,510 --> 00:35:36,750 adds something. 613 00:35:36,750 --> 00:35:38,900 And we do, because we're adding a note. 614 00:35:38,900 --> 00:35:41,720 Last, let's give our button a color. 615 00:35:41,720 --> 00:35:46,290 So we're going to say android: tint. 616 00:35:46,290 --> 00:35:48,965 And you can start by saying @color. 617 00:35:48,965 --> 00:35:51,510 And again, there's a bunch of colors here that are listed. 618 00:35:51,510 --> 00:35:54,540 I'm just going to pick this one, sort of a background color 619 00:35:54,540 --> 00:35:57,472 for a light background. 620 00:35:57,472 --> 00:35:59,680 So that's everything with our floating action button. 621 00:35:59,680 --> 00:36:03,010 So now, we've styled this pretty nicely. 622 00:36:03,010 --> 00:36:07,750 So now, let's build our application and make sure there are no errors. 623 00:36:07,750 --> 00:36:10,545 So let's come up here to build. 624 00:36:10,545 --> 00:36:12,340 Yup, looks like we have an error. 625 00:36:12,340 --> 00:36:14,890 So let's jump over here. 626 00:36:14,890 --> 00:36:17,770 Looks like there's some kind of problem with our database. 627 00:36:17,770 --> 00:36:19,470 So let's come over here. 628 00:36:19,470 --> 00:36:23,550 And, yeah, here, so rather than doing the data access object, 629 00:36:23,550 --> 00:36:25,710 we want to use the entity. 630 00:36:25,710 --> 00:36:30,360 So recall that Note is what we decorated with the @entity annotation. 631 00:36:30,360 --> 00:36:33,990 So we just want to make sure that that's the note, not the note data access 632 00:36:33,990 --> 00:36:36,060 object. 633 00:36:36,060 --> 00:36:39,973 So now if we rebuild, now we've compiled successfully. 634 00:36:39,973 --> 00:36:42,890 So let's run the app and just take a look at what this floating action 635 00:36:42,890 --> 00:36:44,830 button looks like. 636 00:36:44,830 --> 00:36:46,580 Looks like we've installed successfully. 637 00:36:46,580 --> 00:36:48,512 So let's pull up our emulator. 638 00:36:48,512 --> 00:36:49,470 That looks pretty nice. 639 00:36:49,470 --> 00:36:51,250 So we have a RecyclerView here. 640 00:36:51,250 --> 00:36:54,370 It's empty, because we haven't created any notes yet. 641 00:36:54,370 --> 00:36:57,760 Now we have this nice button over here that, when we press it, 642 00:36:57,760 --> 00:36:59,240 doesn't do anything. 643 00:36:59,240 --> 00:37:02,710 So let's hook up an action to this floating action button. 644 00:37:02,710 --> 00:37:07,210 To add an action, let's jump back to our MainActivity. 645 00:37:07,210 --> 00:37:12,290 And in onCreate, let's grab that floating action button. 646 00:37:12,290 --> 00:37:15,410 So we'll create a button object. 647 00:37:15,410 --> 00:37:18,110 And we'll set this equal to findViewById. 648 00:37:18,110 --> 00:37:23,270 And we called this add_note_button. 649 00:37:23,270 --> 00:37:27,020 So with this button object, we can call that same method we called before, 650 00:37:27,020 --> 00:37:32,090 which was setOnClickListener. 651 00:37:32,090 --> 00:37:35,305 And this took one argument, which was a view.onClickListener. 652 00:37:35,305 --> 00:37:38,820 653 00:37:38,820 --> 00:37:42,380 See if we can get the auto complete here. 654 00:37:42,380 --> 00:37:43,632 There we go. 655 00:37:43,632 --> 00:37:47,940 And so remember, we're just overwriting this one method called onClick. 656 00:37:47,940 --> 00:37:51,730 And so when we click this button, we want to do two things. 657 00:37:51,730 --> 00:37:55,020 The first thing we want to do is create a new note. 658 00:37:55,020 --> 00:37:59,310 So let's get that note data access object just like we did last time. 659 00:37:59,310 --> 00:38:01,260 Say database.noteDao. 660 00:38:01,260 --> 00:38:03,930 And this time, we're going to call create. 661 00:38:03,930 --> 00:38:06,900 And that's going to create a new note. 662 00:38:06,900 --> 00:38:09,810 Next, let's reload the adapter. 663 00:38:09,810 --> 00:38:12,320 So let's call adapter.reload. 664 00:38:12,320 --> 00:38:15,630 And that's going to tell the adapter that now that we've created a new note, 665 00:38:15,630 --> 00:38:19,390 let's refresh the RecyclerView so that we can see it in action. 666 00:38:19,390 --> 00:38:20,550 So let's try this out. 667 00:38:20,550 --> 00:38:22,800 Let's run this app. 668 00:38:22,800 --> 00:38:23,820 Here's our emulator. 669 00:38:23,820 --> 00:38:26,833 Let's give our action button a click. 670 00:38:26,833 --> 00:38:27,500 And there we go. 671 00:38:27,500 --> 00:38:30,470 Here's a row that represents our new note. 672 00:38:30,470 --> 00:38:32,690 The contents of this row are the contents 673 00:38:32,690 --> 00:38:35,210 of the note, which is just new note. 674 00:38:35,210 --> 00:38:37,160 So we're off to a good start. 675 00:38:37,160 --> 00:38:42,870 Next, let's hook up a new activity to display the full contents of a note 676 00:38:42,870 --> 00:38:45,120 and enable the user to change it. 677 00:38:45,120 --> 00:38:48,500 So remember to do that, we're going to come over here to the left, 678 00:38:48,500 --> 00:38:53,150 we're going to say new activity, and we're just 679 00:38:53,150 --> 00:38:56,135 going to create an empty activity. 680 00:38:56,135 --> 00:38:59,970 And we're going to call this are NoteActivity. 681 00:38:59,970 --> 00:39:03,620 682 00:39:03,620 --> 00:39:06,980 All right, so that created a Java class and a layout. 683 00:39:06,980 --> 00:39:09,450 Let's go to the layout first. 684 00:39:09,450 --> 00:39:13,500 So here, let's just create a really simple EditText. 685 00:39:13,500 --> 00:39:17,940 So EditText is actually a subclass of TextView. 686 00:39:17,940 --> 00:39:20,850 And as its name suggests, it's editable, instead of just 687 00:39:20,850 --> 00:39:24,700 being a read-only string of text. 688 00:39:24,700 --> 00:39:29,340 So let's just set this to be the entire width of the screen. 689 00:39:29,340 --> 00:39:32,160 So we're just going to match_parent on both of those. 690 00:39:32,160 --> 00:39:34,410 And then let's set an ID, because we know that we're 691 00:39:34,410 --> 00:39:37,480 going to need to access that later. 692 00:39:37,480 --> 00:39:40,890 So we'll call this note_edit_text. 693 00:39:40,890 --> 00:39:42,750 And that's it. 694 00:39:42,750 --> 00:39:48,410 So now, let's open up that new class that was generated, this NoteActivity. 695 00:39:48,410 --> 00:39:54,743 As we always do, let's create a field here for this EditText. 696 00:39:54,743 --> 00:39:56,410 And let's grab a hold of it in onCreate. 697 00:39:56,410 --> 00:40:03,530 698 00:40:03,530 --> 00:40:04,670 OK. 699 00:40:04,670 --> 00:40:06,410 So we want to do two things. 700 00:40:06,410 --> 00:40:12,650 When this activity is created, we want to set the text of this EditText 701 00:40:12,650 --> 00:40:15,020 to be the note that's in the database. 702 00:40:15,020 --> 00:40:17,270 So that way, when we open this up for the first time, 703 00:40:17,270 --> 00:40:19,850 the user just sees what was there before. 704 00:40:19,850 --> 00:40:24,290 The other thing we want to do is when the user leaves this activity, 705 00:40:24,290 --> 00:40:29,670 we want to save the current contents of that EditText back to the database. 706 00:40:29,670 --> 00:40:31,800 So let's do those two things. 707 00:40:31,800 --> 00:40:37,250 So now that we have a reference to this EditText, let's set the contents to be 708 00:40:37,250 --> 00:40:40,190 the contents of the note the user selected. 709 00:40:40,190 --> 00:40:42,860 To do that, we're going to do just what we did last time. 710 00:40:42,860 --> 00:40:46,220 We're going to use an intent to pass the contents from one 711 00:40:46,220 --> 00:40:48,600 activity to the other. 712 00:40:48,600 --> 00:40:53,040 So let's assume that our intent has defined something like contents. 713 00:40:53,040 --> 00:41:01,150 We'll say String contents is get getIntent().getStringExtra() called 714 00:41:01,150 --> 00:41:02,500 contents. 715 00:41:02,500 --> 00:41:09,100 So now we'll just set the text of the EditText to be those contents. 716 00:41:09,100 --> 00:41:10,720 So that's loading the note. 717 00:41:10,720 --> 00:41:15,430 And the other thing we want to do is to save the note. 718 00:41:15,430 --> 00:41:20,680 So to do that, we're going to use another method called onPause. 719 00:41:20,680 --> 00:41:25,270 So where onCreate is called when the activity is first created, 720 00:41:25,270 --> 00:41:29,830 onPause it's going to be called when you leave the activity. 721 00:41:29,830 --> 00:41:33,790 So just as before, let's make sure we call super. 722 00:41:33,790 --> 00:41:40,940 And so now we want to use that database NotesDao to save the contents to disk. 723 00:41:40,940 --> 00:41:44,920 So let's just save the id of the note that this activity represents 724 00:41:44,920 --> 00:41:45,650 in a field. 725 00:41:45,650 --> 00:41:47,760 So we'll say private int id. 726 00:41:47,760 --> 00:41:50,180 And let's just use the intent to store that, 727 00:41:50,180 --> 00:41:54,710 so we'll say id is getIntent().getIntExtra(). 728 00:41:54,710 --> 00:41:59,470 And we'll call that id and we'll just give it a default value of 0. 729 00:41:59,470 --> 00:42:04,900 Now in onPause, we can use that same database object. 730 00:42:04,900 --> 00:42:08,290 So we'll say MainActivity.database.noteDao(). 731 00:42:08,290 --> 00:42:10,540 And now we're going to call save. 732 00:42:10,540 --> 00:42:13,640 And remember that save takes two arguments. 733 00:42:13,640 --> 00:42:15,880 The first one is the contents of the note. 734 00:42:15,880 --> 00:42:18,190 The second one is the id of the note. 735 00:42:18,190 --> 00:42:23,300 Contents of the note, that's going to be from the current text field. 736 00:42:23,300 --> 00:42:28,510 So that's going to be editText.getText() is going to get me the text 737 00:42:28,510 --> 00:42:30,130 that's currently in there. 738 00:42:30,130 --> 00:42:34,640 And then we just saved the is, so I can just call id right there. 739 00:42:34,640 --> 00:42:37,750 So now this says, before this activity is closed, 740 00:42:37,750 --> 00:42:41,110 when the user hits that back button, let's persist everything 741 00:42:41,110 --> 00:42:43,220 that we have to disk. 742 00:42:43,220 --> 00:42:46,670 So now, let's write the other half of this interaction. 743 00:42:46,670 --> 00:42:51,300 So let's come back to our notes adapter. 744 00:42:51,300 --> 00:42:55,090 And just like we did last time, we want to attach a click listener 745 00:42:55,090 --> 00:42:58,380 to the container. 746 00:42:58,380 --> 00:43:01,150 So we're going to say containerView.setOnClickListener. 747 00:43:01,150 --> 00:43:05,030 748 00:43:05,030 --> 00:43:07,155 Let the autocomplete generate that for us. 749 00:43:07,155 --> 00:43:09,030 And so this is going to feel pretty familiar. 750 00:43:09,030 --> 00:43:10,520 We want to create an intent. 751 00:43:10,520 --> 00:43:15,150 We want to set the id and the contents extras field of the intent. 752 00:43:15,150 --> 00:43:17,520 And then we want to start the activity. 753 00:43:17,520 --> 00:43:21,710 So we need to make sure that this view holder has a reference to the note. 754 00:43:21,710 --> 00:43:23,960 So to do that, remember what we did last time. 755 00:43:23,960 --> 00:43:28,880 We said holder.containerView and we used this setTag method. 756 00:43:28,880 --> 00:43:31,640 So we'll pass along the current note right there. 757 00:43:31,640 --> 00:43:35,200 758 00:43:35,200 --> 00:43:38,590 Now, we can say my note-- 759 00:43:38,590 --> 00:43:42,880 current note is going to be my containerView.getTag. 760 00:43:42,880 --> 00:43:44,980 Remember we just have to cast this to a note, 761 00:43:44,980 --> 00:43:48,580 because this is just a regular object by default. 762 00:43:48,580 --> 00:43:51,590 OK, so now let's create our intent. 763 00:43:51,590 --> 00:43:54,820 Remember the way to do that is by creating a new-- 764 00:43:54,820 --> 00:43:57,280 first make sure we're importing it. 765 00:43:57,280 --> 00:44:00,490 Create a new intent. 766 00:44:00,490 --> 00:44:02,870 And the intent is going to take a couple of arguments. 767 00:44:02,870 --> 00:44:07,120 The first one is that context object and the second one 768 00:44:07,120 --> 00:44:10,270 is the class that we want to go use. 769 00:44:10,270 --> 00:44:13,210 That's going to be NoteActivity.class. 770 00:44:13,210 --> 00:44:17,110 Now using that note object, let's put in those extras. 771 00:44:17,110 --> 00:44:20,760 Let's say Intent.putExtra(). 772 00:44:20,760 --> 00:44:24,480 We have the id of our note and that's going to be current.id. 773 00:44:24,480 --> 00:44:27,360 774 00:44:27,360 --> 00:44:35,285 And we have the contents of the note and that's going to be current.contents. 775 00:44:35,285 --> 00:44:37,860 776 00:44:37,860 --> 00:44:39,960 Lastly, let's just start the activity. 777 00:44:39,960 --> 00:44:44,810 So we're going to say getContext.startActivity, 778 00:44:44,810 --> 00:44:46,790 pass along that intent. 779 00:44:46,790 --> 00:44:49,570 So now when the user taps that row, they're 780 00:44:49,570 --> 00:44:52,100 going to see the contents of the note. 781 00:44:52,100 --> 00:44:57,440 Last but not least, we have to make sure we're reloading the notes every time 782 00:44:57,440 --> 00:44:59,000 the user comes back. 783 00:44:59,000 --> 00:45:03,590 Because remember, that notes list is displaying a preview of the note text. 784 00:45:03,590 --> 00:45:08,570 We want to refresh that every time a user finishes editing a note. 785 00:45:08,570 --> 00:45:10,820 So to do that, we're going to use a third method. 786 00:45:10,820 --> 00:45:14,090 We've seen onCreate and we've seen onPause. 787 00:45:14,090 --> 00:45:18,650 We're going to use one more called onResume. 788 00:45:18,650 --> 00:45:22,940 So onResume is going to be called every time an activity is 789 00:45:22,940 --> 00:45:25,070 brought to the foreground. 790 00:45:25,070 --> 00:45:29,390 So when the activity is first created, it's going to call onCreate. 791 00:45:29,390 --> 00:45:32,150 And then it's going to call onResume, because the activity just 792 00:45:32,150 --> 00:45:33,470 entered the foreground. 793 00:45:33,470 --> 00:45:37,190 Then we could jump off to some other activity and come back 794 00:45:37,190 --> 00:45:39,350 and then onResume is going to be called again, 795 00:45:39,350 --> 00:45:41,430 because we're back in the foreground. 796 00:45:41,430 --> 00:45:45,590 So this is a great method to reload our RecyclerView. 797 00:45:45,590 --> 00:45:49,790 So rather than reloading the RecyclerView here in onCreate, 798 00:45:49,790 --> 00:45:52,730 we're just going to move this down to onResume. 799 00:45:52,730 --> 00:45:55,400 And so this will both reload when the app starts up 800 00:45:55,400 --> 00:45:58,310 and every time the user comes back. 801 00:45:58,310 --> 00:46:00,410 So now let's give this a shot. 802 00:46:00,410 --> 00:46:04,844 Let's run our application. 803 00:46:04,844 --> 00:46:08,880 OK, looks like we have one error here. 804 00:46:08,880 --> 00:46:14,620 So it looks like when we call getText, it returns this editable object. 805 00:46:14,620 --> 00:46:17,313 So we forgot to just change that to a string. 806 00:46:17,313 --> 00:46:18,480 Luckily, that's really easy. 807 00:46:18,480 --> 00:46:20,890 We can just say .toString. 808 00:46:20,890 --> 00:46:24,120 So let's try running this again. 809 00:46:24,120 --> 00:46:26,400 Looks like we built successfully. 810 00:46:26,400 --> 00:46:28,170 So here's that RecyclerView again. 811 00:46:28,170 --> 00:46:29,910 Let's tap on a note. 812 00:46:29,910 --> 00:46:32,820 And OK, it looks like we got a crash. 813 00:46:32,820 --> 00:46:36,900 So let's take a look at our log and see what happened. 814 00:46:36,900 --> 00:46:41,055 So we open up our log and we can see here in red, attempt to read from field 815 00:46:41,055 --> 00:46:42,840 on a null object reference. 816 00:46:42,840 --> 00:46:46,440 OK, so it even told us it's in NotesAdapter, line 31. 817 00:46:46,440 --> 00:46:48,210 So I can actually just click that and it's 818 00:46:48,210 --> 00:46:51,510 going to jump me right to where my exception happened. 819 00:46:51,510 --> 00:46:54,535 So it looks like here current is null. 820 00:46:54,535 --> 00:46:55,660 Now let's think about this. 821 00:46:55,660 --> 00:46:59,160 So it looks like we're setting current in the constructor, 822 00:46:59,160 --> 00:47:03,600 but that's not right, because when we invoke the constructor, as up 823 00:47:03,600 --> 00:47:07,080 here in onCreate view holder. 824 00:47:07,080 --> 00:47:10,950 But we're actually setting the tag in onBindViewHolder. 825 00:47:10,950 --> 00:47:14,730 So instead of having this getTag here, we actually 826 00:47:14,730 --> 00:47:16,560 want to put it inside of our onClick. 827 00:47:16,560 --> 00:47:19,360 828 00:47:19,360 --> 00:47:22,660 So now let's try rerunning the app again. 829 00:47:22,660 --> 00:47:25,150 OK, we compiled successfully. 830 00:47:25,150 --> 00:47:27,630 Let's try again and tap on this row. 831 00:47:27,630 --> 00:47:32,370 And great, so looks like we've loaded this note from our database. 832 00:47:32,370 --> 00:47:33,210 So that worked out. 833 00:47:33,210 --> 00:47:36,000 Let's try testing it out by saving the note. 834 00:47:36,000 --> 00:47:38,380 So I'm going to-- 835 00:47:38,380 --> 00:47:41,900 this is a test note. 836 00:47:41,900 --> 00:47:46,670 OK, I'm going to use the back button to come back to my list. 837 00:47:46,670 --> 00:47:49,640 And great, it looks like we've saved it to the database 838 00:47:49,640 --> 00:47:53,240 and we've successfully reloaded it in our RecyclerView. 839 00:47:53,240 --> 00:47:57,050 So before we finish up, let's just add some last finishing touches to make 840 00:47:57,050 --> 00:47:59,330 our app look a little bit nicer. 841 00:47:59,330 --> 00:48:02,460 Let's start with our note activity. 842 00:48:02,460 --> 00:48:05,960 So there are a couple of things I wanted to change about that edit text. 843 00:48:05,960 --> 00:48:08,810 First is it was kind of weird that the text was centered, 844 00:48:08,810 --> 00:48:12,710 so let's move the gravity of that text to be at the top. 845 00:48:12,710 --> 00:48:15,520 846 00:48:15,520 --> 00:48:19,550 So we're going to set the android: gravity to top. 847 00:48:19,550 --> 00:48:22,140 And so now rather than centering that text, 848 00:48:22,140 --> 00:48:25,530 that's going to put the text at the top of the edit text. 849 00:48:25,530 --> 00:48:28,080 Let's also add a little bit of padding, just so the text 850 00:48:28,080 --> 00:48:29,620 doesn't run up against the screen. 851 00:48:29,620 --> 00:48:31,170 So let's say padding. 852 00:48:31,170 --> 00:48:33,230 Let's use 10 pixels for that. 853 00:48:33,230 --> 00:48:37,890 Lastly, we have that weird kind of pink bar at the bottom of the edit text. 854 00:48:37,890 --> 00:48:41,370 We can get rid of that just by setting the background property. 855 00:48:41,370 --> 00:48:44,820 So let's set at @android background to be 856 00:48:44,820 --> 00:48:50,800 equal to this @android color/transparent. 857 00:48:50,800 --> 00:48:54,390 And so that's going to make sure that we have that transparency. 858 00:48:54,390 --> 00:48:57,450 OK, so now that our second activity looks a bit nicer. 859 00:48:57,450 --> 00:49:01,470 Let's come back to that first activity and apply those same changes 860 00:49:01,470 --> 00:49:03,535 from our other app. 861 00:49:03,535 --> 00:49:05,410 So we're going to set a couple of properties. 862 00:49:05,410 --> 00:49:09,300 One is going to be make sure it's clickable. 863 00:49:09,300 --> 00:49:12,757 So we'll set clickable flexible to be true. 864 00:49:12,757 --> 00:49:14,340 Let's space out the rows a little bit. 865 00:49:14,340 --> 00:49:18,360 We'll say android: padding is 10 pixels. 866 00:49:18,360 --> 00:49:21,100 And lastly, let's add that nice ripple effect, 867 00:49:21,100 --> 00:49:25,170 which was foreground and then you can say 868 00:49:25,170 --> 00:49:29,060 android_attr/selectableitembackground. 869 00:49:29,060 --> 00:49:32,430 And so this will just make that RecyclerView look a bit nicer again. 870 00:49:32,430 --> 00:49:34,590 So let's take a look at these aesthetic changes 871 00:49:34,590 --> 00:49:37,080 by running the app one more time. 872 00:49:37,080 --> 00:49:39,450 All right, let's pull up the emulator. 873 00:49:39,450 --> 00:49:41,010 So now a row is looking a bit nicer. 874 00:49:41,010 --> 00:49:42,400 There's some more padding. 875 00:49:42,400 --> 00:49:45,000 If I tap this, I get that nice ripple effect. 876 00:49:45,000 --> 00:49:48,030 And then that kind of weird background is gone. 877 00:49:48,030 --> 00:49:49,770 So that's it for our notes app. 878 00:49:49,770 --> 00:49:53,070 To recap, we've made an app, used a RecyclerView to display 879 00:49:53,070 --> 00:49:55,620 a list of contents from our database, and then we 880 00:49:55,620 --> 00:49:58,290 wrote our DOA to save notes, to create notes, 881 00:49:58,290 --> 00:50:00,290 and to get them all from the database. 882 00:50:00,290 --> 00:50:03,840 And so now, you can write Android apps to save settings and other things 883 00:50:03,840 --> 00:50:08,000 to the user's phone, so they can have them when they open the app again. 884 00:50:08,000 --> 00:50:09,165