1 00:00:04,660 --> 00:00:07,000 Alright so moving on now. We're going 2 00:00:07,000 --> 00:00:09,160 to talk about onUpgrade, the function, 3 00:00:09,160 --> 00:00:11,500 and also some testing. So the other 4 00:00:11,500 --> 00:00:12,760 function we had to implement, if you 5 00:00:12,760 --> 00:00:14,980 recall, to our, in our AppDatabase 6 00:00:14,980 --> 00:00:18,640 class was onUpgrade. And if we take 7 00:00:18,640 --> 00:00:22,480 a look at that, looking at the 8 00:00:22,480 --> 00:00:26,500 documentation - let's scroll this up so 9 00:00:26,500 --> 00:00:29,619 we can see it - it gets past the version 10 00:00:29,619 --> 00:00:32,020 of the database that Android finds. So 11 00:00:32,020 --> 00:00:33,460 the documentation explains that this 12 00:00:33,460 --> 00:00:35,110 function's called when the database 13 00:00:35,110 --> 00:00:37,150 needs to be upgraded. 14 00:00:37,150 --> 00:00:39,400 Now when the function's called, it 15 00:00:39,400 --> 00:00:41,320 gets passed the version of the database 16 00:00:41,320 --> 00:00:43,930 that Android finds, and the current 17 00:00:43,930 --> 00:00:46,420 version. So we passed the current version 18 00:00:46,420 --> 00:00:48,490 number into the super method in the 19 00:00:48,490 --> 00:00:50,800 constructor, so the SQLiteOpen 20 00:00:50,800 --> 00:00:52,900 Helper class can track the versions for 21 00:00:52,900 --> 00:00:54,940 us. Now we're obviously just starting 22 00:00:54,940 --> 00:00:57,130 out so this is version 1, so there's 23 00:00:57,130 --> 00:00:58,930 nothing to upgrade. We'll be adding some 24 00:00:58,930 --> 00:01:00,670 more tables and views as we develop the 25 00:01:00,670 --> 00:01:02,500 app, so I'm going to be discussing the on 26 00:01:02,500 --> 00:01:04,869 Upgrade function in more detail when 27 00:01:04,869 --> 00:01:05,920 we've actually got an upgrade to 28 00:01:05,920 --> 00:01:07,780 perform. For now though what we're going 29 00:01:07,780 --> 00:01:09,009 to do is, we're just going to of add some 30 00:01:09,009 --> 00:01:13,840 dummy code and some logging. Alright so I'm 31 00:01:13,840 --> 00:01:16,210 going to start with some logging, Log 32 00:01:16,210 --> 00:01:18,789 .d parentheses TAG comma double quotes 33 00:01:18,789 --> 00:01:27,609 onUpgrade colon starts. Alright, and 34 00:01:27,609 --> 00:01:30,280 we're going to type when in parentheses, 35 00:01:30,280 --> 00:01:34,539 old Version, and open a code block and 36 00:01:34,539 --> 00:01:37,149 then we're going to type 1 dash greater than sign 37 00:01:37,149 --> 00:01:39,999 and a code block. And I'm just going to put a 38 00:01:39,999 --> 00:01:43,030 comment in there, "upgrade logic from 39 00:01:43,030 --> 00:01:46,389 version 1". Then outside of that what we're 40 00:01:46,389 --> 00:01:48,939 going to do is, do an else dash greater 41 00:01:48,939 --> 00:01:51,999 than, and we're going do throw Illegal 42 00:01:51,999 --> 00:01:55,600 StateException, in the parentheses, on 43 00:01:55,600 --> 00:01:57,999 Upgrade parentheses in double quotes, 44 00:01:57,999 --> 00:02:04,810 with unknown newVersion colon space, and 45 00:02:04,810 --> 00:02:06,899 that's going to be $newVersion. 46 00:02:06,899 --> 00:02:09,729 Alright. Now we can create a new instance 47 00:02:09,729 --> 00:02:12,400 of our AppDdatabase class in Main 48 00:02:12,400 --> 00:02:14,680 Activity's onCreate method, and request 49 00:02:14,680 --> 00:02:16,300 a database connection to test that it 50 00:02:16,300 --> 00:02:19,500 works. So let's go back to our MainActivity, 51 00:02:19,500 --> 00:02:22,000 and specifically the onCreate method - 52 00:02:22,000 --> 00:02:24,670 we're going to do just that. So I'm going 53 00:02:24,670 --> 00:02:27,040 to start typing this code below the set 54 00:02:27,040 --> 00:02:30,160 SupportActionBar - give it a space 55 00:02:30,160 --> 00:02:32,500 there. So I'm going to start typing val 56 00:02:32,500 --> 00:02:38,800 appDatabase equals AppDatabase dot 57 00:02:38,800 --> 00:02:41,910 getInstance, then this in parenthesis. 58 00:02:41,910 --> 00:02:45,880 Then we're going to type val db equals 59 00:02:45,880 --> 00:02:51,340 appDatabase.readableDatabase. Then next 60 00:02:51,340 --> 00:02:54,700 line, val cursor is equal to db.raw 61 00:02:54,700 --> 00:02:56,920 query, and in parentheses I'm going to 62 00:02:56,920 --> 00:03:04,060 type SELECT * FROM Tasks comma then 63 00:03:04,060 --> 00:03:06,640 null - that's the second argument. Then I'm going to 64 00:03:06,640 --> 00:03:11,050 do a Log.d parentheses TAG comma 65 00:03:11,050 --> 00:03:12,280 and I'm just going to do a series of 66 00:03:12,280 --> 00:03:17,230 asterisks there, and I'm gonna take 67 00:03:17,230 --> 00:03:20,260 the opportunity now to add our tag at the 68 00:03:20,260 --> 00:03:24,370 start of the file. So private const val TAG 69 00:03:24,370 --> 00:03:29,320 equals MainActivity. Okay, and then below 70 00:03:29,320 --> 00:03:32,130 the log entry we're going to do cursor 71 00:03:32,130 --> 00:03:36,280 dot use. Open a code block, and then 72 00:03:36,280 --> 00:03:37,270 we're going to type on the next line, 73 00:03:37,270 --> 00:03:43,530 while parentheses it.moveToNext, 74 00:03:43,530 --> 00:03:46,930 another code block. And a comment here 75 00:03:46,930 --> 00:03:48,360 that were going to "Cycle through all 76 00:03:48,360 --> 00:03:54,990 records", and then we're going to type with 77 00:03:54,990 --> 00:03:59,410 parentheses cursor. Open yet another 78 00:03:59,410 --> 00:04:01,930 code block and type val id equals get 79 00:04:01,930 --> 00:04:06,730 Long zero in parentheses, and val name is 80 00:04:06,730 --> 00:04:10,980 equal to getString, 1 in parentheses, 81 00:04:10,980 --> 00:04:16,870 val description equals getString, 2 in 82 00:04:16,870 --> 00:04:20,560 parentheses and then sortOrder, val sort 83 00:04:20,560 --> 00:04:25,750 Order equals getString, 3 in parentheses. 84 00:04:25,750 --> 00:04:28,510 And I'm going to type val result is 85 00:04:28,510 --> 00:04:32,469 equal to, in double quotes, ID colon 86 00:04:32,469 --> 00:04:38,169 space and $id full stop and name colon space 87 00:04:38,169 --> 00:04:40,389 dollar name. Then I'm going to go space 88 00:04:40,389 --> 00:04:45,340 there, then description colon dollar 89 00:04:45,340 --> 00:04:51,219 description in sort order colon $ sort 90 00:04:51,219 --> 00:04:54,219 Order. Then we're going to add another log 91 00:04:54,219 --> 00:04:57,629 there, so Log.d parentheses TAG comma. 92 00:04:57,629 --> 00:05:03,249 It's going to be onCreate reading data 93 00:05:03,249 --> 00:05:07,870 $result, and then finally what I'm 94 00:05:07,870 --> 00:05:10,060 going to do, is take a copy of this, these 95 00:05:10,060 --> 00:05:11,979 Asterisks, and I'm going to add that 96 00:05:11,979 --> 00:05:15,449 just above the fab.setOnClickListener there. 97 00:05:15,449 --> 00:05:18,129 Alright so what's this code doing? Well 98 00:05:18,129 --> 00:05:19,689 after getting an instance of AppDdatabase, 99 00:05:19,689 --> 00:05:22,210 we run a query and log the task details. 100 00:05:22,210 --> 00:05:24,249 This is very similar to the code we've 101 00:05:24,249 --> 00:05:26,319 seen previously. We won't be performing 102 00:05:26,319 --> 00:05:28,659 queries like this in the app though. This is 103 00:05:28,659 --> 00:05:30,550 just a test that our AppDatabase class 104 00:05:30,550 --> 00:05:33,580 is behaving as it should. Now I've added 105 00:05:33,580 --> 00:05:35,169 a row of asterisks as you saw there, 106 00:05:35,169 --> 00:05:37,180 before and after our data, because the 107 00:05:37,180 --> 00:05:39,069 new logcat makes it harder to spot 108 00:05:39,069 --> 00:05:42,039 our data. Alright, so now let's run our 109 00:05:42,039 --> 00:05:43,810 application. So I'm going to click on the 110 00:05:43,810 --> 00:05:47,649 button to start it, and I'm going to 111 00:05:47,649 --> 00:05:50,469 open our logcat, just so we can take a 112 00:05:50,469 --> 00:05:52,779 look and see what's happened. So firstly, 113 00:05:52,779 --> 00:05:54,669 the getInstance function returns a new 114 00:05:54,669 --> 00:05:56,289 instance of our singleton AppDatabase 115 00:05:56,289 --> 00:05:58,360 class, and we can see the constructor 116 00:05:58,360 --> 00:06:01,839 being called, here. We've got our App 117 00:06:01,839 --> 00:06:03,460 Database initializing on the next line, 118 00:06:03,460 --> 00:06:06,490 and then onCreate starting, and if you 119 00:06:06,490 --> 00:06:09,339 recall onCreate - that function's called 120 00:06:09,339 --> 00:06:10,479 for us because the android framework 121 00:06:10,479 --> 00:06:12,310 detects that the database doesn't 122 00:06:12,310 --> 00:06:14,800 already exist. So onCreate was called, as 123 00:06:14,800 --> 00:06:16,300 we can see there, and there's our SQL 124 00:06:16,300 --> 00:06:19,479 code. That's the code that creates the 125 00:06:19,479 --> 00:06:21,610 database when that onCreate 126 00:06:21,610 --> 00:06:23,469 function's called for us, because the 127 00:06:23,469 --> 00:06:25,779 Android framework detected that the 128 00:06:25,779 --> 00:06:28,060 database didn't already exist. So, so far 129 00:06:28,060 --> 00:06:30,339 so good. This is really showing us what 130 00:06:30,339 --> 00:06:33,069 we expected to be shown, or in other 131 00:06:33,069 --> 00:06:34,870 words, the functionalities working as 132 00:06:34,870 --> 00:06:36,909 expected. But what we want to do now is 133 00:06:36,909 --> 00:06:38,409 check that the database really was 134 00:06:38,409 --> 00:06:41,529 created, and does in fact contain our 135 00:06:41,529 --> 00:06:43,839 Tasks table. So what we're going to do 136 00:06:43,839 --> 00:06:45,550 now is close the logcat. 137 00:06:45,550 --> 00:06:48,610 I'm going to open Terminal. We're going 138 00:06:48,610 --> 00:06:50,140 to have a look at the database on the 139 00:06:50,140 --> 00:06:52,450 emulator. So I'm going to start by typing adb 140 00:06:52,450 --> 00:06:57,190 devices. Now most of the time when you do 141 00:06:57,190 --> 00:06:59,170 that, you'll only have a single device 142 00:06:59,170 --> 00:07:01,420 showing here. But I've got an emulator 143 00:07:01,420 --> 00:07:04,540 and my one-plus Android phone connected, 144 00:07:04,540 --> 00:07:06,640 and I've done it that way just so you 145 00:07:06,640 --> 00:07:09,130 can see how to use adb shell when 146 00:07:09,130 --> 00:07:10,470 there's more than one device available. 147 00:07:10,470 --> 00:07:12,730 But you'll get an error if you try to 148 00:07:12,730 --> 00:07:14,650 use adb commands with more than one 149 00:07:14,650 --> 00:07:17,170 device connected to the computer, whether 150 00:07:17,170 --> 00:07:19,020 they're emulators or physical devices. 151 00:07:19,020 --> 00:07:22,150 Now the reason for the error is that adb 152 00:07:22,150 --> 00:07:24,520 doesn't know which device you want to 153 00:07:24,520 --> 00:07:26,950 use. If there's only one it doesn't have 154 00:07:26,950 --> 00:07:28,480 a problem, but if you've got more than 155 00:07:28,480 --> 00:07:30,730 one then you have to specify which 156 00:07:30,730 --> 00:07:33,460 device you want to use. We do that with 157 00:07:33,460 --> 00:07:36,790 the dash s switch. So my emulator is showing 158 00:07:36,790 --> 00:07:39,820 up as emulator-5554, so the 159 00:07:39,820 --> 00:07:42,340 command I need to type here is adb 160 00:07:42,340 --> 00:07:50,040 space -s space emulator-5554 161 00:07:50,040 --> 00:07:54,550 space shell. So basically you can see 162 00:07:54,550 --> 00:07:56,830 that's connected now to the emulator, and 163 00:07:56,830 --> 00:07:58,000 whenever you've got more than one device 164 00:07:58,000 --> 00:08:00,270 connected just use -s and the device 165 00:08:00,270 --> 00:08:01,420 ID 166 00:08:01,420 --> 00:08:04,210 immediately after adb, and, which 167 00:08:04,210 --> 00:08:05,890 specifies which device should be used. 168 00:08:05,890 --> 00:08:08,140 Alright, so we're connected now to shell 169 00:08:08,140 --> 00:08:11,980 on our emulator, so let's type su. We 170 00:08:11,980 --> 00:08:14,740 need that super user mode, and that 171 00:08:14,740 --> 00:08:16,180 probably won't work if you're using a 172 00:08:16,180 --> 00:08:18,520 physical device, unless you've got root 173 00:08:18,520 --> 00:08:20,740 access and you've also installed the su 174 00:08:20,740 --> 00:08:23,080 command. So if you're testing this app on 175 00:08:23,080 --> 00:08:25,900 a physical device, you'll probably have 176 00:08:25,900 --> 00:08:27,850 to skip this step. But don't worry though, 177 00:08:27,850 --> 00:08:28,780 were already confirming that the 178 00:08:28,780 --> 00:08:31,150 database has been created. If it hadn't 179 00:08:31,150 --> 00:08:32,980 been then we would have seen errors in 180 00:08:32,980 --> 00:08:35,169 the logcat. Now we saw in an earlier 181 00:08:35,169 --> 00:08:37,720 video that the databases 182 00:08:37,720 --> 00:08:39,940 are created in the apps directory, in 183 00:08:39,940 --> 00:08:42,460 /data/data in a database 184 00:08:42,460 --> 00:08:44,590 directory. So make a note of your package 185 00:08:44,590 --> 00:08:46,510 name, because that's also the name of the 186 00:08:46,510 --> 00:08:48,550 apps home directory if you're using a 187 00:08:48,550 --> 00:08:50,590 different package name to me. In my case 188 00:08:50,590 --> 00:08:52,810 I'm going to type cd /data, that's 189 00:08:52,810 --> 00:08:55,630 forward slash, /data again. That's 190 00:08:55,630 --> 00:08:57,490 going to be learnprogramming.academy 191 00:08:57,490 --> 00:08:58,880 dot tasktimer. 192 00:08:58,880 --> 00:08:59,990 You can see that coming up automatically 193 00:08:59,990 --> 00:09:02,540 when I clicked, when I pressed tab, and I'm 194 00:09:02,540 --> 00:09:05,240 going to go into databases. Alright, so now 195 00:09:05,240 --> 00:09:06,770 that I've done that I'm going to type 196 00:09:06,770 --> 00:09:12,740 sqlite3 Tasktimer.db, and then 197 00:09:12,740 --> 00:09:16,670 I'm going to type .schema, and 198 00:09:16,670 --> 00:09:19,190 there's our Tasks table. Now remember 199 00:09:19,190 --> 00:09:21,320 that Android is a Linux operating system 200 00:09:21,320 --> 00:09:23,270 and the file and directory names are 201 00:09:23,270 --> 00:09:25,820 case sensitive. So if your Task timer 202 00:09:25,820 --> 00:09:27,290 database didn't open, 203 00:09:27,290 --> 00:09:29,540 make sure you've used the correct case 204 00:09:29,540 --> 00:09:31,880 for the name. Now this should be exactly 205 00:09:31,880 --> 00:09:33,740 the same as the database underscore name 206 00:09:33,740 --> 00:09:36,800 field in the AppDatabase class. Now while 207 00:09:36,800 --> 00:09:38,150 we're here, I'm going to add some records 208 00:09:38,150 --> 00:09:39,950 to the database. Now we're going to write 209 00:09:39,950 --> 00:09:41,870 the code to display the tasks before the 210 00:09:41,870 --> 00:09:44,060 code to add them, so these sample rows 211 00:09:44,060 --> 00:09:45,860 will let us see that the display code's 212 00:09:45,860 --> 00:09:47,720 working when we get to that point in 213 00:09:47,720 --> 00:09:49,760 development. So I'm going to type 214 00:09:49,760 --> 00:09:55,340 INSERT INTO Tasks parentheses Name comma 215 00:09:55,340 --> 00:10:01,520 Description VALUES parentheses Task 216 00:10:01,520 --> 00:10:03,440 Timer single quotes comma, single 217 00:10:03,440 --> 00:10:08,420 quote for Tasktimer app creation, and 218 00:10:08,420 --> 00:10:10,070 close off the single quote, right 219 00:10:10,070 --> 00:10:13,010 parentheses and semicolon. Then next one, 220 00:10:13,010 --> 00:10:15,880 we'll do INSERT INTO Tasks again, 221 00:10:15,880 --> 00:10:18,010 parentheses, it's going to be Name 222 00:10:18,010 --> 00:10:22,280 Description and SortOrder, separated by 223 00:10:22,280 --> 00:10:24,500 commas, and another parentheses to close 224 00:10:24,500 --> 00:10:26,800 it off - a right one - then VALUES 225 00:10:26,800 --> 00:10:29,120 parentheses. We're going to go with 226 00:10:29,120 --> 00:10:33,140 Android Java single quotes comma, 227 00:10:33,140 --> 00:10:37,480 single quotes again, Android Java course 228 00:10:37,480 --> 00:10:40,520 single quote comma, two right parentheses 229 00:10:40,520 --> 00:10:43,760 and semicolon. Alright, the third I'm 230 00:10:43,760 --> 00:10:46,990 going to type INSERT INTO Tasks 231 00:10:46,990 --> 00:10:50,680 parentheses Name comma Description comma 232 00:10:50,680 --> 00:10:54,790 and SortOrder comma right parentheses, 233 00:10:54,790 --> 00:10:58,850 VALUES and parentheses again. This time I'm going 234 00:10:58,850 --> 00:11:02,960 to type Android Kotlin and I'm going to type 235 00:11:02,960 --> 00:11:07,339 Android Kotlin course - which of course 236 00:11:07,339 --> 00:11:10,100 is this one - comma zero right parentheses 237 00:11:10,100 --> 00:11:11,070 and 238 00:11:11,070 --> 00:11:14,850 semicolon. Then we do a SELECT * FROM Tasks to 239 00:11:14,850 --> 00:11:17,400 make sure that the records are there. We 240 00:11:17,400 --> 00:11:19,290 can see the records are there. So at this 241 00:11:19,290 --> 00:11:21,480 point our database is looking fine. So 242 00:11:21,480 --> 00:11:22,530 we're going to quit sqlite by 243 00:11:22,530 --> 00:11:26,160 typing .exit, then we're going to leave 244 00:11:26,160 --> 00:11:28,320 super user mode by typing exit, without the 245 00:11:28,320 --> 00:11:30,450 dot time. Then we're going to log 246 00:11:30,450 --> 00:11:31,830 out of the Android shell by typing exit 247 00:11:31,830 --> 00:11:35,840 once more. Then I can type exit one more time 248 00:11:35,840 --> 00:11:39,090 and that closes the Terminal window. Al 249 00:11:39,090 --> 00:11:40,410 right, so now there's some data in the 250 00:11:40,410 --> 00:11:42,630 database. We should see it logged in the 251 00:11:42,630 --> 00:11:45,030 logcat when we run the app again, so let's 252 00:11:45,030 --> 00:11:46,920 go and try running that and see that it 253 00:11:46,920 --> 00:11:54,690 works. We'll open logcat. Alright so 254 00:11:54,690 --> 00:11:56,280 that's looking good. Our AppDatabase 255 00:11:56,280 --> 00:11:58,500 class created the database, and is now 256 00:11:58,500 --> 00:12:00,210 providing a database connection that we 257 00:12:00,210 --> 00:12:02,850 can use. We've now got the Tasks Contract 258 00:12:02,850 --> 00:12:05,430 and AppDatabase classes working. The 259 00:12:05,430 --> 00:12:07,290 next step is to create the Content 260 00:12:07,290 --> 00:12:09,660 Provider that we use to access the data 261 00:12:09,660 --> 00:12:11,790 in the database, and we'll start work on 262 00:12:11,790 --> 00:12:14,960 that in the next video.