1 00:00:04,540 --> 00:00:06,519 Alright so let's move on now to the 2 00:00:06,519 --> 00:00:08,440 insert function. So we're going to start 3 00:00:08,440 --> 00:00:09,910 off with the same code that we've used 4 00:00:09,910 --> 00:00:11,740 in the two other functions. We're going to 5 00:00:11,740 --> 00:00:14,139 check the URI and get a result back from 6 00:00:14,139 --> 00:00:15,969 the uriMatcher. So what I'm going to 7 00:00:15,969 --> 00:00:18,390 do is just take a copy of the code that 8 00:00:18,390 --> 00:00:21,130 we've used in the query function, and 9 00:00:21,130 --> 00:00:23,650 come down and we're going to start by 10 00:00:23,650 --> 00:00:26,260 pasting that over the TODO in our 11 00:00:26,260 --> 00:00:30,010 insert function. Now the code that uses 12 00:00:30,010 --> 00:00:31,869 this function will often need to know 13 00:00:31,869 --> 00:00:34,780 the ID of the new row, so this function 14 00:00:34,780 --> 00:00:38,800 returns a URI that includes the ID. Now 15 00:00:38,800 --> 00:00:40,899 the function accepts a URI without an ID 16 00:00:40,899 --> 00:00:43,899 and returns the same URI with an ID 17 00:00:43,899 --> 00:00:47,739 added. So let's start coding this, and one 18 00:00:47,739 --> 00:00:49,089 thing we are going to do slightly 19 00:00:49,089 --> 00:00:51,190 differently to the query method, is get a 20 00:00:51,190 --> 00:00:53,679 writable database object in each of 21 00:00:53,679 --> 00:00:55,210 these cases. So let's start by typing 22 00:00:55,210 --> 00:01:01,510 some code. So val recordId : Long and 23 00:01:01,510 --> 00:01:06,159 then val returnUri : 24 00:01:06,159 --> 00:01:11,700 Uri. Alright, so we now need to add a 25 00:01:11,700 --> 00:01:14,680 block here, a when match block, so I'm 26 00:01:14,680 --> 00:01:17,580 going to type when and parentheses match, 27 00:01:17,580 --> 00:01:21,070 then left and right curly braces. We want 28 00:01:21,070 --> 00:01:23,380 to go through and check firstly for TASKS. 29 00:01:23,380 --> 00:01:27,180 So TASKS, add the arrow as we normally do 30 00:01:27,180 --> 00:01:29,980 for a when, and then in there we're going 31 00:01:29,980 --> 00:01:33,610 to type val db equals AppDatabase dot 32 00:01:33,610 --> 00:01:37,330 getInstance, in parentheses context, and 33 00:01:37,330 --> 00:01:41,560 dot writableDatabase. I'm going to do 34 00:01:41,560 --> 00:01:44,230 exactly the same thing and take a copy 35 00:01:44,230 --> 00:01:49,840 OF those three lines for the TIMINGS, for 36 00:01:49,840 --> 00:01:55,000 TIMINGS as well. Alright. So in the query 37 00:01:55,000 --> 00:01:56,800 method we've got a readableDatabase 38 00:01:56,800 --> 00:01:59,140 from our AppDatabase. Here, for obvious 39 00:01:59,140 --> 00:02:00,909 reasons, because we're inserting data, 40 00:02:00,909 --> 00:02:03,040 inserting new rows, we're getting a 41 00:02:03,040 --> 00:02:05,590 writableDatabase instead. Now the get 42 00:02:05,590 --> 00:02:07,479 ReadableDatabase and getWritable 43 00:02:07,479 --> 00:02:09,758 Database functions can be quite slow, so 44 00:02:09,758 --> 00:02:12,010 we want to avoid calling them if an 45 00:02:12,010 --> 00:02:15,310 invalid URI's used. Now we do that in 46 00:02:15,310 --> 00:02:17,139 the query function by not calling get 47 00:02:17,139 --> 00:02:17,860 ReadableData 48 00:02:17,860 --> 00:02:20,860 base until after the switch. If the URI 49 00:02:20,860 --> 00:02:23,740 was invalid, an exception is thrown and 50 00:02:23,740 --> 00:02:25,960 the final bit of code isn't executed. In 51 00:02:25,960 --> 00:02:28,600 the insert method we need to use the db 52 00:02:28,600 --> 00:02:31,180 in each of our cases. Now it might look more 53 00:02:31,180 --> 00:02:32,410 natural to get the writable 54 00:02:32,410 --> 00:02:34,930 Database before the when, but that means 55 00:02:34,930 --> 00:02:36,910 we'll be calling getWritableDatabase 56 00:02:36,910 --> 00:02:39,130 before we've checked that the URI is 57 00:02:39,130 --> 00:02:41,320 valid. The other thing to note here, is 58 00:02:41,320 --> 00:02:43,450 that we're not using the TASK_ 59 00:02:43,450 --> 00:02:46,720 DURATIONS URI values. The database 60 00:02:46,720 --> 00:02:48,880 view is only used for querying the 61 00:02:48,880 --> 00:02:51,880 database, not for writing to it. That 62 00:02:51,880 --> 00:02:53,500 means we don't need to include it in the 63 00:02:53,500 --> 00:02:57,160 insert, update or delete functions. Now as 64 00:02:57,160 --> 00:02:59,170 well as the URI, this function will 65 00:02:59,170 --> 00:03:01,870 receive a ContentValues object holding 66 00:03:01,870 --> 00:03:03,700 the values to insert. We'll look at 67 00:03:03,700 --> 00:03:05,739 ContentValues later. Firstly, what I'm 68 00:03:05,739 --> 00:03:08,620 going to do is add an else here and then I'm 69 00:03:08,620 --> 00:03:10,690 going to add the code for inserting into 70 00:03:10,690 --> 00:03:15,520 the two tables. So for our when, else, in 71 00:03:15,520 --> 00:03:17,320 that case with the arrow we're 72 00:03:17,320 --> 00:03:19,780 going to throw an IllegalArgument 73 00:03:19,780 --> 00:03:24,519 Exception, parentheses, we're going to put 74 00:03:24,519 --> 00:03:29,019 Unknown uri colon then a dollar 75 00:03:29,019 --> 00:03:30,310 sign uri, just so we've got something 76 00:03:30,310 --> 00:03:32,350 to show on the screen. 77 00:03:32,350 --> 00:03:35,650 And in terms of writing the database, or 78 00:03:35,650 --> 00:03:37,330 writing to the database, we're going to 79 00:03:37,330 --> 00:03:40,810 put recordId is equal to db.insert, 80 00:03:40,810 --> 00:03:43,060 and in parentheses it's going to be the 81 00:03:43,060 --> 00:03:45,430 name of our table. In this case it's Tasks 82 00:03:45,430 --> 00:03:48,450 Contract.TABLE_NAME comma 83 00:03:48,450 --> 00:03:54,790 null comma values. And for the TIMINGS what 84 00:03:54,790 --> 00:03:55,870 we're going to do is something very 85 00:03:55,870 --> 00:03:59,910 similar, recordId equals db.insert. 86 00:03:59,910 --> 00:04:02,850 This time it'll be the TimingsContract 87 00:04:02,850 --> 00:04:08,890 dot TABLE_NAME comma null comma values. So 88 00:04:08,890 --> 00:04:12,190 the insertion's done by the db's insert 89 00:04:12,190 --> 00:04:14,650 function. Now we give it the name of the 90 00:04:14,650 --> 00:04:16,478 table to insert into and the list of 91 00:04:16,478 --> 00:04:19,000 values to insert. So whatever the Content 92 00:04:19,000 --> 00:04:21,370 Values object is we're just passing that 93 00:04:21,370 --> 00:04:23,830 on to the database insert method. So if 94 00:04:23,830 --> 00:04:24,850 you have a quick look at the Content 95 00:04:24,850 --> 00:04:27,729 Values up here in the parameters, you can 96 00:04:27,729 --> 00:04:30,099 see here that it says "This class is used to 97 00:04:30,099 --> 00:04:31,389 store a set of values 98 00:04:31,389 --> 00:04:33,550 that the ContentResolver can process". 99 00:04:33,550 --> 00:04:36,069 It's very similar to a bundle, in fact, 100 00:04:36,069 --> 00:04:38,020 and we'll look at this in more detail 101 00:04:38,020 --> 00:04:40,900 when we come to create a ContentValues 102 00:04:40,900 --> 00:04:42,759 object, which we'll do when we use this 103 00:04:42,759 --> 00:04:45,689 insert function. So close that down, and 104 00:04:45,689 --> 00:04:47,919 remember that we changed the function 105 00:04:47,919 --> 00:04:49,930 signature earlier. There's no point 106 00:04:49,930 --> 00:04:51,639 trying to insert no values into the 107 00:04:51,639 --> 00:04:54,009 table, so we made the ContentValues 108 00:04:54,009 --> 00:04:57,159 parameter a non null type by removing 109 00:04:57,159 --> 00:04:59,080 the question mark. Now the second 110 00:04:59,080 --> 00:05:00,639 parameter here, which we're passing null 111 00:05:00,639 --> 00:05:02,919 to - you can see here the name is null 112 00:05:02,919 --> 00:05:05,319 ColumnHack - that's an interesting name, 113 00:05:05,319 --> 00:05:07,389 and if we have a look at the insert 114 00:05:07,389 --> 00:05:10,569 statement here. So open the documentation 115 00:05:10,569 --> 00:05:13,360 for that - it talks about what that is. So 116 00:05:13,360 --> 00:05:15,580 basically, if every column except the 117 00:05:15,580 --> 00:05:17,919 underscore ID column of course, can 118 00:05:17,919 --> 00:05:20,110 accept null values, then the values 119 00:05:20,110 --> 00:05:22,060 parameter might contain nothing but 120 00:05:22,060 --> 00:05:22,539 nulls. 121 00:05:22,539 --> 00:05:24,759 Now SQLite doesn't allow the SQL 122 00:05:24,759 --> 00:05:26,770 insert statement that will result from 123 00:05:26,770 --> 00:05:28,509 that. There'd be no column names 124 00:05:28,509 --> 00:05:30,909 specified and a statement wouldn't be 125 00:05:30,909 --> 00:05:32,979 valid SQL. So in that case you'd 126 00:05:32,979 --> 00:05:34,599 specify a column for this second 127 00:05:34,599 --> 00:05:36,729 parameter, just to make the SQL 128 00:05:36,729 --> 00:05:39,069 statement valid. But there's not a lot of 129 00:05:39,069 --> 00:05:41,020 point really inserting a completely null 130 00:05:41,020 --> 00:05:43,539 record most of the time, but it is 131 00:05:43,539 --> 00:05:45,819 possible, and if you needed to do it for 132 00:05:45,819 --> 00:05:47,919 some reason then you just specify one of 133 00:05:47,919 --> 00:05:50,770 your table columns for that argument. Now 134 00:05:50,770 --> 00:05:53,050 our tables won't accept a completely null 135 00:05:53,050 --> 00:05:55,539 record. The names column is set to be not 136 00:05:55,539 --> 00:05:57,430 null, so therefore we don't need to worry 137 00:05:57,430 --> 00:05:59,680 about this parameter and we can safely 138 00:05:59,680 --> 00:06:01,469 ignore it by passing null. 139 00:06:01,469 --> 00:06:05,319 Now if the insert works the db insert 140 00:06:05,319 --> 00:06:08,229 function will return the ID of the new 141 00:06:08,229 --> 00:06:11,500 row. So what we can do is make sure that 142 00:06:11,500 --> 00:06:13,960 it's not returned as -1, the 143 00:06:13,960 --> 00:06:15,279 value's not returned as -1, 144 00:06:15,279 --> 00:06:18,279 and then append it to the URI using a 145 00:06:18,279 --> 00:06:20,650 contractBuildUriFromId method, if 146 00:06:20,650 --> 00:06:22,870 that's the case. Now if the return value 147 00:06:22,870 --> 00:06:25,569 is -1 then the insert failed, 148 00:06:25,569 --> 00:06:27,610 and we saw that in the documentation for 149 00:06:27,610 --> 00:06:29,680 the db insert method. In that case we'll 150 00:06:29,680 --> 00:06:32,650 throw an exception, just briefly again, it 151 00:06:32,650 --> 00:06:34,599 talks about here "or -1 if an 152 00:06:34,599 --> 00:06:37,419 error occurred". So let's write the code 153 00:06:37,419 --> 00:06:40,539 for that. So under the recordId we're 154 00:06:40,539 --> 00:06:41,899 going to put if 155 00:06:41,899 --> 00:06:47,129 recordId is not equal to -1, then 156 00:06:47,129 --> 00:06:48,869 we're going, actually what we need to 157 00:06:48,869 --> 00:06:50,279 do there also - and I'll talk about this 158 00:06:50,279 --> 00:06:52,589 in a moment - we need to put the L 159 00:06:52,589 --> 00:06:55,080 after the -1 to say that it's a 160 00:06:55,080 --> 00:06:57,270 Long. So if it's not equal to 161 00:06:57,270 --> 00:06:59,869 -1 you're going to put returnUri 162 00:06:59,869 --> 00:07:05,669 equals TasksContract.buildUri 163 00:07:05,669 --> 00:07:09,569 FromId recordId. Then what we're going 164 00:07:09,569 --> 00:07:11,219 to do is have an else there, and the else 165 00:07:11,219 --> 00:07:14,309 will be else throw, in this case we're 166 00:07:14,309 --> 00:07:16,740 going to throw an SQL exception with the 167 00:07:16,740 --> 00:07:21,779 message "Fail to insert, Uri was 168 00:07:21,779 --> 00:07:26,099 Łuri". So that's essentially 169 00:07:26,099 --> 00:07:28,679 the logic there, and I'm going to take a copy 170 00:07:28,679 --> 00:07:31,949 of this code because it's very similar and I'll 171 00:07:31,949 --> 00:07:36,269 paste that for the TIMINGS, the TIMINGS 172 00:07:36,269 --> 00:07:37,979 code, and I'm going to change Tasks 173 00:07:37,979 --> 00:07:40,529 Contract here. That's going to be equal 174 00:07:40,529 --> 00:07:45,899 to TimingsContract. Now in relation to 175 00:07:45,899 --> 00:07:49,259 this -1L, Kotlin doesn't allow a 176 00:07:49,259 --> 00:07:51,479 comparison between long and int, which is 177 00:07:51,479 --> 00:07:53,339 why we have to compare our recordId to 178 00:07:53,339 --> 00:07:56,249 -1l, to specify the long value 179 00:07:56,249 --> 00:07:58,379 -1, and you saw that there was an 180 00:07:58,379 --> 00:08:00,899 error there if I left the L out. And as you 181 00:08:00,899 --> 00:08:02,789 saw the code for the TIMINGS case is 182 00:08:02,789 --> 00:08:04,469 almost identical. You just use the 183 00:08:04,469 --> 00:08:06,659 constants from TimingsContract instead 184 00:08:06,659 --> 00:08:08,279 of TasksContract. You can see that I've 185 00:08:08,279 --> 00:08:11,219 made those two changes to cater for the 186 00:08:11,219 --> 00:08:12,839 fact that that's different to the Tasks 187 00:08:12,839 --> 00:08:15,689 Contract for the tasks component. And 188 00:08:15,689 --> 00:08:18,300 just to finish off now we need to come 189 00:08:18,300 --> 00:08:21,179 down here. We need to return something so 190 00:08:21,179 --> 00:08:22,319 we're going to do some logging first. So 191 00:08:22,319 --> 00:08:25,979 Log.d parentheses TAG comma, and we'll 192 00:08:25,979 --> 00:08:31,009 type Exiting insert, returning $ 193 00:08:31,009 --> 00:08:36,019 returnUri, and we're just going to return 194 00:08:36,019 --> 00:08:38,448 returnUri. 195 00:08:38,448 --> 00:08:42,779 that's essentially our insert method. The 196 00:08:42,779 --> 00:08:44,579 update method, which we'll start working 197 00:08:44,579 --> 00:08:47,009 on in the next video, is a mix of query and 198 00:08:47,009 --> 00:08:49,139 insert. It's code will be very similar to 199 00:08:49,139 --> 00:08:52,019 query but we won't return a cursor. Now 200 00:08:52,019 --> 00:08:54,059 when inserting, we're only inserting a 201 00:08:54,059 --> 00:08:55,440 single record at a time. 202 00:08:55,440 --> 00:08:57,449 When updating though, we may update the 203 00:08:57,449 --> 00:08:59,759 columns of a single row, or in fact we 204 00:08:59,759 --> 00:09:02,220 could update many rows at once. You might, 205 00:09:02,220 --> 00:09:03,779 for example, want to update the Sort 206 00:09:03,779 --> 00:09:06,480 Order column for all tasks with, say the same 207 00:09:06,480 --> 00:09:08,370 description. So we'll start working on 208 00:09:08,370 --> 00:09:10,500 writing that update function in the next 209 00:09:10,500 --> 00:09:12,740 video.