1 00:00:04,680 --> 00:00:06,629 Alright so let's talk about the App 2 00:00:06,629 --> 00:00:09,629 Database class. So in the previous video 3 00:00:09,629 --> 00:00:13,020 we created a Tasks Contract class that 4 00:00:13,020 --> 00:00:15,959 defines the column names for our Tasks 5 00:00:15,959 --> 00:00:18,810 table. Now that might seem a little bit 6 00:00:18,810 --> 00:00:20,910 over the top just to declare a few 7 00:00:20,910 --> 00:00:23,250 string constants, but as we create more 8 00:00:23,250 --> 00:00:25,740 code you'll see why we've bothered 9 00:00:25,740 --> 00:00:28,350 creating this. In this video we'll create 10 00:00:28,350 --> 00:00:31,170 the database class that will handle 11 00:00:31,170 --> 00:00:34,079 creating our database. And it'll also 12 00:00:34,079 --> 00:00:36,690 provide the database object that our 13 00:00:36,690 --> 00:00:39,149 Content Provider is going to need when 14 00:00:39,149 --> 00:00:41,820 it comes to access the database. So let's 15 00:00:41,820 --> 00:00:44,130 start by creating the App Database class. 16 00:00:44,130 --> 00:00:45,870 I'm going to right click on the package, 17 00:00:45,870 --> 00:00:50,070 New, Kotlin File/Class and AppDatabase 18 00:00:50,070 --> 00:00:53,700 being the name. Now I'm going to make 19 00:00:53,700 --> 00:00:56,129 this internal, because the only thing 20 00:00:56,129 --> 00:00:57,719 that should ever use this class will be 21 00:00:57,719 --> 00:01:00,059 our Content Provider. I'm going to type 22 00:01:00,059 --> 00:01:04,078 internal class AppDatabase, left and 23 00:01:04,078 --> 00:01:06,420 right curly braces. In fact, what I'll do 24 00:01:06,420 --> 00:01:08,310 is, I'll add a comment to that effect at 25 00:01:08,310 --> 00:01:11,010 the start of the class. I'm going to add 26 00:01:11,010 --> 00:01:13,220 it here and we're going to say "Basic 27 00:01:13,220 --> 00:01:18,960 database class for the application." and 28 00:01:18,960 --> 00:01:21,000 "The only class that should use this is 29 00:01:21,000 --> 00:01:27,590 Approvider", 30 00:01:27,590 --> 00:01:29,600 and Approvider's going to be in left 31 00:01:29,600 --> 00:01:31,270 and right square brackets. 32 00:01:31,270 --> 00:01:33,619 And notice how that got highlighted when 33 00:01:33,619 --> 00:01:35,030 I typed that in left and right square 34 00:01:35,030 --> 00:01:36,710 brackets, but more on that 35 00:01:36,710 --> 00:01:39,049 in a moment. So when you start a comment 36 00:01:39,049 --> 00:01:40,909 with a forward slash and two stars or 37 00:01:40,909 --> 00:01:43,100 two asterisks, that indicates what's 38 00:01:43,100 --> 00:01:45,709 known as a doc comment - also known as a 39 00:01:45,709 --> 00:01:48,140 KDoc. And it's very similar to the 40 00:01:48,140 --> 00:01:50,990 Java doc comments, but some things such 41 00:01:50,990 --> 00:01:53,869 as links have been simplified. Now you 42 00:01:53,869 --> 00:01:54,920 may have noticed this type of 43 00:01:54,920 --> 00:01:57,079 comment in the Android Java source code 44 00:01:57,079 --> 00:01:58,640 that we've looked at. There's quite a 45 00:01:58,640 --> 00:02:00,860 formal structure to these doc comments, 46 00:02:00,860 --> 00:02:02,810 and you may have noticed this when we 47 00:02:02,810 --> 00:02:05,360 looked at documentation previously in 48 00:02:05,360 --> 00:02:06,950 this course for a method slash function. 49 00:02:06,950 --> 00:02:09,889 So the content looks like a formatted 50 00:02:09,889 --> 00:02:11,239 version of the comments in the source 51 00:02:11,239 --> 00:02:13,400 code, and there is a reason for that. 52 00:02:13,400 --> 00:02:15,500 That's because the documentation is 53 00:02:15,500 --> 00:02:17,780 generated from those comments using the 54 00:02:17,780 --> 00:02:20,540 Java doc tool. Now in Kotlin the same 55 00:02:20,540 --> 00:02:23,569 applies but, the tool's called Dokka. Now 56 00:02:23,569 --> 00:02:25,579 I won't be discussing doc comments in 57 00:02:25,579 --> 00:02:28,040 this course, but I'll start using them to 58 00:02:28,040 --> 00:02:29,560 comment some of the code that we write. 59 00:02:29,560 --> 00:02:32,060 Now you find loads of information 60 00:02:32,060 --> 00:02:34,160 on-line, including the Kotlin 61 00:02:34,160 --> 00:02:38,739 documentation. Let's go and check that out. 62 00:02:38,739 --> 00:02:40,670 So this here you can see, that's 63 00:02:40,670 --> 00:02:43,160 information about documenting Kotlin 64 00:02:43,160 --> 00:02:46,579 code. And actually I planned to show 65 00:02:46,579 --> 00:02:49,160 you this KDoc appearing when we used 66 00:02:49,160 --> 00:02:51,079 the AppDatabase class in our code, 67 00:02:51,079 --> 00:02:54,260 but unfortunately the Dokka plug-in for 68 00:02:54,260 --> 00:02:56,410 Android studio is currently broken. 69 00:02:56,410 --> 00:02:58,819 Hopefully they'll fix it soon, but as of 70 00:02:58,819 --> 00:03:00,799 the time I'm recording this video, it 71 00:03:00,799 --> 00:03:03,230 causes the Gradle builds to 72 00:03:03,230 --> 00:03:05,630 crash which means that you can't compile 73 00:03:05,630 --> 00:03:07,220 and run your apps. That's pretty severe, 74 00:03:07,220 --> 00:03:09,169 so for that reason we're not going to 75 00:03:09,169 --> 00:03:11,269 use it. So although we can't see it 76 00:03:11,269 --> 00:03:13,370 working, it's still a good idea to 77 00:03:13,370 --> 00:03:16,400 include doc comments in your classes. So 78 00:03:16,400 --> 00:03:17,859 I'll just switch back to Android Studio. 79 00:03:17,859 --> 00:03:20,870 Now these KDoc strings 80 00:03:20,870 --> 00:03:23,780 are parsed by Android Studio, and 81 00:03:23,780 --> 00:03:25,340 we've actually got a warning over here. We can 82 00:03:25,340 --> 00:03:27,079 see if we hover over this AppProvider 83 00:03:27,079 --> 00:03:28,940 in square brackets, and also the warning 84 00:03:28,940 --> 00:03:30,919 over here in the gutter that we can't 85 00:03:30,919 --> 00:03:33,590 resolve - symbol AppProvider. That's 86 00:03:33,590 --> 00:03:35,209 because it hasn't been written yet, so 87 00:03:35,209 --> 00:03:36,439 don't worry about that warning at the 88 00:03:36,439 --> 00:03:38,239 moment. Alright but getting back to this 89 00:03:38,239 --> 00:03:40,700 class, this AppDatabase class will 90 00:03:40,700 --> 00:03:41,420 extend 91 00:03:41,420 --> 00:03:43,640 the SQLiteOpenHelper class that 92 00:03:43,640 --> 00:03:45,590 Android provides to make using sqlite 93 00:03:45,590 --> 00:03:47,330 databases easier. So let's go 94 00:03:47,330 --> 00:03:48,080 ahead and add that - 95 00:03:48,080 --> 00:03:51,230 so the colon after the AppDatabase space 96 00:03:51,230 --> 00:03:55,989 and SQLiteOpenHelper parentheses. 97 00:03:55,989 --> 00:03:58,160 Now we've got some errors at the moment. 98 00:03:58,160 --> 00:04:00,500 The SQLiteOpenHelper class has 99 00:04:00,500 --> 00:04:02,000 some abstract methods that we need to 100 00:04:02,000 --> 00:04:04,130 implement. It's got no idea whether, or 101 00:04:04,130 --> 00:04:05,840 what the structure of our database 102 00:04:05,840 --> 00:04:08,030 should be, for example, so it leaves it up 103 00:04:08,030 --> 00:04:09,769 to our class to implement the onCreate 104 00:04:09,769 --> 00:04:12,590 function. But before implementing that 105 00:04:12,590 --> 00:04:14,300 function and also the onUpgrade 106 00:04:14,300 --> 00:04:16,760 function, there's another error because 107 00:04:16,760 --> 00:04:18,620 the SQLiteOpenHelper class needs 108 00:04:18,620 --> 00:04:23,120 some arguments in its constructor. You 109 00:04:23,120 --> 00:04:24,350 can see when I hover over to that 110 00:04:24,350 --> 00:04:26,570 warning, or that error rather, that 111 00:04:26,570 --> 00:04:28,400 makes it clearer that we need to do 112 00:04:28,400 --> 00:04:30,320 that. So it needs some arguments to 113 00:04:30,320 --> 00:04:32,990 its constructor. So those are a context - 114 00:04:32,990 --> 00:04:35,720 the name and version of our database - and 115 00:04:35,720 --> 00:04:37,729 also something called a CursorFactory. 116 00:04:37,729 --> 00:04:40,340 Now the database name and version can be 117 00:04:40,340 --> 00:04:43,010 declared as constants, and I'll also add 118 00:04:43,010 --> 00:04:44,540 a constant tag for logging, so let's go 119 00:04:44,540 --> 00:04:46,729 ahead and do that. I'll add those above 120 00:04:46,729 --> 00:04:49,850 the class definition here, so private 121 00:04:49,850 --> 00:04:55,010 const Val TAG is equal to, in double 122 00:04:55,010 --> 00:04:58,910 quotes, AppDatabase. Then next we've got 123 00:04:58,910 --> 00:05:02,539 private const Val DATABASE underscore 124 00:05:02,539 --> 00:05:05,780 NAME in uppercase, which unsurprisingly 125 00:05:05,780 --> 00:05:08,150 is our database name. That was Task 126 00:05:08,150 --> 00:05:12,260 Timer.db, and we also want a 127 00:05:12,260 --> 00:05:14,900 const for the version; private const 128 00:05:14,900 --> 00:05:17,840 val DATABASE_VERSION, again in 129 00:05:17,840 --> 00:05:21,680 uppercase, equals 3. And now that 130 00:05:21,680 --> 00:05:24,200 we've done that we can expand on the 131 00:05:24,200 --> 00:05:27,080 class definition line on line 19. 132 00:05:27,080 --> 00:05:29,390 So let's first add a constructor for App 133 00:05:29,390 --> 00:05:33,560 Database - so after the AppDatabase type 134 00:05:33,560 --> 00:05:35,930 constructor. Then in parentheses we're 135 00:05:35,930 --> 00:05:37,610 going to type context in lower case, 136 00:05:37,610 --> 00:05:40,520 colon Contexts with a capital C, 137 00:05:40,520 --> 00:05:43,639 which is using the Android, or coming 138 00:05:43,639 --> 00:05:46,310 from android.content. And if we scroll up 139 00:05:46,310 --> 00:05:47,810 we can see now that import has 140 00:05:47,810 --> 00:05:48,410 been added. 141 00:05:48,410 --> 00:05:50,900 Then over to the right for the 142 00:05:50,900 --> 00:05:52,760 SQLiteOpenHelper, we need to pass those 143 00:05:52,760 --> 00:05:54,620 parameters now. So the 144 00:05:54,620 --> 00:05:57,620 first one is going to be context - let's 145 00:05:57,620 --> 00:06:00,470 add that. Next we want to pass the 146 00:06:00,470 --> 00:06:03,770 DATABASE_NAME. Next we're going to pass a 147 00:06:03,770 --> 00:06:05,419 null and I'll talk about that shortly - 148 00:06:05,419 --> 00:06:07,520 the CursorFactory - and lastly the 149 00:06:07,520 --> 00:06:10,220 DATABASE_VERSION. So that's fixed 150 00:06:10,220 --> 00:06:12,949 one of those errors now, and if we hover over 151 00:06:12,949 --> 00:06:14,479 here now, it's now just complaining about 152 00:06:14,479 --> 00:06:16,790 the fact we haven't implemented the 153 00:06:16,790 --> 00:06:19,639 methods. Alright, so what we've done 154 00:06:19,639 --> 00:06:21,500 here, is when our AppDatabase instance 155 00:06:21,500 --> 00:06:23,720 is created it'll be passed a context 156 00:06:23,720 --> 00:06:25,970 now. That's needed as the first argument 157 00:06:25,970 --> 00:06:28,580 in the SQLiteOpenHelper 158 00:06:28,580 --> 00:06:30,740 constructor, which we've now added. The 159 00:06:30,740 --> 00:06:32,810 DATABASE_NAME as the second argument is 160 00:06:32,810 --> 00:06:34,669 obvious, and we'll see why we need a 161 00:06:34,669 --> 00:06:36,169 version later which was the fourth 162 00:06:36,169 --> 00:06:38,660 argument, later in the course. But for the 163 00:06:38,660 --> 00:06:40,520 CursorFactory - the third argument - I've 164 00:06:40,520 --> 00:06:43,550 specified null. You can create your own 165 00:06:43,550 --> 00:06:45,680 class to create custom cursors if you 166 00:06:45,680 --> 00:06:48,770 wish, and one reason for doing that is if 167 00:06:48,770 --> 00:06:50,600 you wanted to log the SQL queries 168 00:06:50,600 --> 00:06:53,810 before they're executed. for example. But 169 00:06:53,810 --> 00:06:55,699 the Cursor class included in Android is 170 00:06:55,699 --> 00:06:58,280 fine, so we're just passing null for that 171 00:06:58,280 --> 00:06:59,900 third argument so that we can use that. 172 00:06:59,900 --> 00:07:02,210 Alright, so at this point I'm going to 173 00:07:02,210 --> 00:07:04,880 do something slightly strange now, and I 174 00:07:04,880 --> 00:07:06,200 don't recommend you doing this in 175 00:07:06,200 --> 00:07:08,539 production code. For reasons that will 176 00:07:08,539 --> 00:07:10,970 become apparent shortly, it'll be useful 177 00:07:10,970 --> 00:07:12,650 to see when a new instance of this class 178 00:07:12,650 --> 00:07:16,010 is created. To do that, what I'm going to 179 00:07:16,010 --> 00:07:17,900 do is add an init block that does 180 00:07:17,900 --> 00:07:19,729 nothing more than log when it's called. 181 00:07:19,729 --> 00:07:21,950 And that's going to be very useful for 182 00:07:21,950 --> 00:07:24,260 us to see what's going on, but as I 183 00:07:24,260 --> 00:07:26,510 mentioned isn't a good idea to use in 184 00:07:26,510 --> 00:07:28,039 your apps. So we're going to go ahead and 185 00:07:28,039 --> 00:07:31,910 add this init block, so it's an init, then add a left 186 00:07:31,910 --> 00:07:34,940 and right curly brace. Then within there 187 00:07:34,940 --> 00:07:36,800 we're just going to add a log - so Log.d 188 00:07:36,800 --> 00:07:39,830 parentheses TAG comma, then in double quotes 189 00:07:39,830 --> 00:07:47,810 AppDatabase colon initializing. OK. Now 190 00:07:47,810 --> 00:07:49,250 we've still got that error because we 191 00:07:49,250 --> 00:07:50,660 haven't implemented those abstract 192 00:07:50,660 --> 00:07:53,210 classes, so let's get Android Studio to 193 00:07:53,210 --> 00:07:57,919 generate those for us. So we'll implement 194 00:07:57,919 --> 00:08:02,750 both onCreate and onUpgrade. Now 195 00:08:02,750 --> 00:08:04,789 the SQLiteOpenHelper class can do 196 00:08:04,789 --> 00:08:07,130 a lot for us, but it can't know the 197 00:08:07,130 --> 00:08:08,129 SQL commands that are 198 00:08:08,129 --> 00:08:11,429 needed to create our database, nor how to 199 00:08:11,429 --> 00:08:12,899 upgrade it from one version to another. 200 00:08:12,899 --> 00:08:15,270 So in other words we have to provide the 201 00:08:15,270 --> 00:08:18,269 implementation of those two methods, and 202 00:08:18,269 --> 00:08:19,409 that's why they're abstract in the 203 00:08:19,409 --> 00:08:22,529 SQLiteOpenHelper class. Alright, so 204 00:08:22,529 --> 00:08:24,749 we've implemented at the moment, empty 205 00:08:24,749 --> 00:08:26,009 versions of both of those that have 206 00:08:26,009 --> 00:08:28,709 only got a TODO in there. And when an 207 00:08:28,709 --> 00:08:31,080 instance of this class is created, the 208 00:08:31,080 --> 00:08:34,229 code in its superclass - which is 209 00:08:34,229 --> 00:08:36,630 SQLiteOpenHelper - will check to see if 210 00:08:36,630 --> 00:08:39,240 the database already exists. Now if 211 00:08:39,240 --> 00:08:41,849 it doesn't exist, our onCreate function 212 00:08:41,849 --> 00:08:44,068 will be called. Now this is where we'll 213 00:08:44,068 --> 00:08:46,800 execute the SQL statements to create 214 00:08:46,800 --> 00:08:49,350 the tables, views and other objects in 215 00:08:49,350 --> 00:08:52,110 our database. At the moment though, we're 216 00:08:52,110 --> 00:08:54,870 focusing on the Tasks table, and we 217 00:08:54,870 --> 00:08:56,550 created the SQL for that in the 218 00:08:56,550 --> 00:08:58,680 previous video. So I'm just going to paste 219 00:08:58,680 --> 00:09:01,110 that in as a comment, so we've got a 220 00:09:01,110 --> 00:09:03,480 reference point for the SQL code we're 221 00:09:03,480 --> 00:09:06,750 ultimately going to be creating. Alright, 222 00:09:06,750 --> 00:09:08,480 and I'll just delete the TODO there. 223 00:09:08,480 --> 00:09:11,730 We'll paste that in as a comment. Alright, 224 00:09:11,730 --> 00:09:13,139 so what we're going to do next is build 225 00:09:13,139 --> 00:09:16,079 up the necessary string to create this 226 00:09:16,079 --> 00:09:18,180 SQL statement, but let's work on that 227 00:09:18,180 --> 00:09:21,380 in the next video.