1
00:00:04,700 --> 00:00:07,040
Alright so we're talking about the Uri

2
00:00:07,040 --> 00:00:09,530
Matcher in the last video, and there's

3
00:00:09,530 --> 00:00:11,960
the link to that UriMatcher class in

4
00:00:11,960 --> 00:00:13,820
the description under Content URI

5
00:00:13,820 --> 00:00:16,640
patterns, on the documentation page for

6
00:00:16,640 --> 00:00:18,529
creating Content Providers. So let's go

7
00:00:18,529 --> 00:00:19,970
and click on that and open it in a new

8
00:00:19,970 --> 00:00:23,869
tab. Let's have a look at this Uri

9
00:00:23,869 --> 00:00:26,990
Matcher class. So this class maps

10
00:00:26,990 --> 00:00:29,779
different content URIs to integer

11
00:00:29,779 --> 00:00:32,210
values, that we can use to decide what

12
00:00:32,210 --> 00:00:35,170
code to execute for various URIs.

13
00:00:35,170 --> 00:00:36,979
And you can see down here that it's

14
00:00:36,979 --> 00:00:40,309
described as a utility class to aid in

15
00:00:40,309 --> 00:00:42,799
matching URIs in content providers.

16
00:00:42,799 --> 00:00:46,339
And you can see there that the example

17
00:00:46,339 --> 00:00:48,170
defines a number of constant int values;

18
00:00:48,170 --> 00:00:50,720
PEOPLE is 1, PEOPLE_ID is

19
00:00:50,720 --> 00:00:53,930
2 and so forth. Most of Google's

20
00:00:53,930 --> 00:00:56,510
example code is still in Java, but it

21
00:00:56,510 --> 00:00:58,010
should be easy to see what's going on

22
00:00:58,010 --> 00:01:00,320
here. If the URI just referred to the

23
00:01:00,320 --> 00:01:02,629
PEOPLE table, the UriMatcher would

24
00:01:02,629 --> 00:01:05,600
return 1. If the URI also had an ID on

25
00:01:05,600 --> 00:01:08,420
the end, then Matcher would return 2. Now

26
00:01:08,420 --> 00:01:10,520
we can't do that magically, so further

27
00:01:10,520 --> 00:01:12,469
down in the example code, as we scroll down

28
00:01:12,469 --> 00:01:14,899
there, there's a lot of calls to the add

29
00:01:14,899 --> 00:01:18,049
URI method. These associate the various

30
00:01:18,049 --> 00:01:20,359
URI patterns with the values

31
00:01:20,359 --> 00:01:23,090
that we want the Matcher to return. For

32
00:01:23,090 --> 00:01:25,640
the people table without an ID, the Matcher

33
00:01:25,640 --> 00:01:27,530
is told to return the value of the

34
00:01:27,530 --> 00:01:30,380
people constant, which is 1. But if an

35
00:01:30,380 --> 00:01:32,840
ID is provided, then this code tells it to

36
00:01:32,840 --> 00:01:35,420
return PEOPLE_ID, which is two.

37
00:01:35,420 --> 00:01:37,549
So I'll talk about that hash in a minute,

38
00:01:37,549 --> 00:01:40,159
but it's just a wild card that'll match

39
00:01:40,159 --> 00:01:42,289
any number. And this example goes a

40
00:01:42,289 --> 00:01:44,539
bit further, and allows all the phone

41
00:01:44,539 --> 00:01:47,119
numbers for a specified person to be

42
00:01:47,119 --> 00:01:49,039
returned - that's PEOPLE_PHONES -

43
00:01:49,039 --> 00:01:51,679
or a specific phone number for that

44
00:01:51,679 --> 00:01:53,689
person - PEOPLE_PHONES

45
00:01:53,689 --> 00:01:56,509
_ID. So you might be asking why

46
00:01:56,509 --> 00:01:59,450
do we need an integer value for each URI?

47
00:01:59,450 --> 00:02:01,609
Well if we didn't use the UriMatcher,

48
00:02:01,609 --> 00:02:03,109
then it would have to do things like

49
00:02:03,109 --> 00:02:05,899
counting how many segments the URI path

50
00:02:05,899 --> 00:02:09,258
contains, then checking the value of each

51
00:02:09,258 --> 00:02:11,470
segment to decide what action to take.

52
00:02:11,470 --> 00:02:13,670
Now a bit further down the page - if I

53
00:02:13,670 --> 00:02:16,150
scroll down - you can see over here that

54
00:02:16,150 --> 00:02:18,440
Google have provided an example

55
00:02:18,440 --> 00:02:20,150
of how we can use a switch statement

56
00:02:20,150 --> 00:02:22,720
with the values returned by the Matcher,

57
00:02:22,720 --> 00:02:25,580
compared to an alternative if we don't

58
00:02:25,580 --> 00:02:28,640
use the Matcher. I can't quite get that

59
00:02:28,640 --> 00:02:30,380
all on the screen but you can see the

60
00:02:30,380 --> 00:02:33,350
gist of it there, and Java uses switch in

61
00:02:33,350 --> 00:02:35,360
case instead of Kotlons when, and the

62
00:02:35,360 --> 00:02:37,340
arrow, the right arrow. But hopefully, you

63
00:02:37,340 --> 00:02:39,140
get the general idea with his code even

64
00:02:39,140 --> 00:02:41,090
if you don't know Java. Now don't actually

65
00:02:41,090 --> 00:02:42,590
worry about these return values at

66
00:02:42,590 --> 00:02:44,690
the moment - we're coming back to those

67
00:02:44,690 --> 00:02:45,230
in a minute.

68
00:02:45,230 --> 00:02:47,810
The important thing here, is that the

69
00:02:47,810 --> 00:02:50,240
code that doesn't use the UriMatcher

70
00:02:50,240 --> 00:02:52,460
is a lot more complicated. So there's a

71
00:02:52,460 --> 00:02:54,340
UriMatcher code, and if I scroll down

72
00:02:54,340 --> 00:02:57,230
you can see there. I think clearly you'd

73
00:02:57,230 --> 00:02:58,610
agree that looks a lot more

74
00:02:58,610 --> 00:03:01,160
complicated, and that's because it has to

75
00:03:01,160 --> 00:03:03,230
check the number of segments, then check

76
00:03:03,230 --> 00:03:05,690
specific segments against a table name.

77
00:03:05,690 --> 00:03:07,550
So it's just more complicated. The Uri

78
00:03:07,550 --> 00:03:10,610
Matcher is making our lives easier by

79
00:03:10,610 --> 00:03:12,470
taking care of the matching, and just

80
00:03:12,470 --> 00:03:14,960
giving us an integer value to use in the

81
00:03:14,960 --> 00:03:17,150
switch statement, and obviously in the

82
00:03:17,150 --> 00:03:19,430
when statement if we're talking Kotlin. So

83
00:03:19,430 --> 00:03:20,870
now that we've been through that we can

84
00:03:20,870 --> 00:03:23,360
add the code for the buildUriMatcher

85
00:03:23,360 --> 00:03:25,489
function now, or rather add the rest of

86
00:03:25,489 --> 00:03:26,030
the code.

87
00:03:26,030 --> 00:03:28,040
Now Google have done it slightly

88
00:03:28,040 --> 00:03:30,200
differently here in the code just above

89
00:03:30,200 --> 00:03:33,070
this. I'll scroll up and have a look there,

90
00:03:33,070 --> 00:03:36,230
and you can see here they've added a static

91
00:03:36,230 --> 00:03:38,600
initializer block to call the addURI

92
00:03:38,600 --> 00:03:40,700
method. Tt'll be interesting to see

93
00:03:40,700 --> 00:03:42,170
what they suggest when they produce a

94
00:03:42,170 --> 00:03:44,450
Kotlin version of this example, but I

95
00:03:44,450 --> 00:03:45,890
suspect they'll do the same as what

96
00:03:45,890 --> 00:03:49,030
we're about to do. So going back to our code,

97
00:03:49,030 --> 00:03:51,980
so our lazy delegate that we defined on

98
00:03:51,980 --> 00:03:55,250
line 34, make sure that the UriMatcher

99
00:03:55,250 --> 00:03:57,260
instance is created when we need it, and

100
00:03:57,260 --> 00:03:59,690
lazy also ensures that there's only one

101
00:03:59,690 --> 00:04:01,970
instance created. Now if you read that

102
00:04:01,970 --> 00:04:04,160
article by Christophe Beyls, you'll

103
00:04:04,160 --> 00:04:06,350
see that he based the singleton holder

104
00:04:06,350 --> 00:04:09,830
class on the Kotlin lazy code. Alright so

105
00:04:09,830 --> 00:04:11,060
let's write a bit of code here now and

106
00:04:11,060 --> 00:04:13,160
expand on the buildUriMatcher 

107
00:04:13,160 --> 00:04:15,050
method. So at the moment we've got, just

108
00:04:15,050 --> 00:04:17,060
pretty well an empty bit of code there -

109
00:04:17,060 --> 00:04:19,579
I'm going to start. Now firstly we'll

110
00:04:19,579 --> 00:04:21,560
look at the first URI we want to

111
00:04:21,560 --> 00:04:25,910
match, and it'll be e.g. content colon

112
00:04:25,910 --> 00:04:28,010
//learn

113
00:04:28,010 --> 00:04:31,249
programming.academy

114
00:04:31,249 --> 00:04:37,039
dot tasktimer.provider/Tasks

115
00:04:37,039 --> 00:04:39,319
with a capital T. So to add that to the

116
00:04:39,319 --> 00:04:40,339
Matcher we're going to type matcher

117
00:04:40,339 --> 00:04:43,519
dot addURI, and then in

118
00:04:43,519 --> 00:04:45,469
parentheses we'll start with our CONTENT

119
00:04:45,469 --> 00:04:48,199
_AUTHORITY comma. Then it'll be

120
00:04:48,199 --> 00:04:52,159
tasksContract dot tables TABLE

121
00:04:52,159 --> 00:04:57,379
_NAME comma, then TASKS. Then the

122
00:04:57,379 --> 00:04:58,549
next thing we want to match, if I just

123
00:04:58,549 --> 00:05:02,539
copy that comment. This time it'll be for

124
00:05:02,539 --> 00:05:05,269
a specific task, /8

125
00:05:05,269 --> 00:05:07,189
for argument's sake, and that would be

126
00:05:07,189 --> 00:05:12,289
mature.addURI, and in parentheses

127
00:05:12,289 --> 00:05:15,259
CONTENT_AUTHORITY comma. This time

128
00:05:15,259 --> 00:05:16,429
it's going to be, in double quotes, dollar

129
00:05:16,429 --> 00:05:19,579
sign left and right curly braces Tasks

130
00:05:19,579 --> 00:05:23,179
Contract.TABLE_NAME, then right,

131
00:05:23,179 --> 00:05:25,219
closing off the curly brace, the right

132
00:05:25,219 --> 00:05:27,799
curly brace there, forward slash and the

133
00:05:27,799 --> 00:05:30,229
hash for the wild card comma. This time

134
00:05:30,229 --> 00:05:34,369
it's going to be TASKS_ID. Then

135
00:05:34,369 --> 00:05:37,189
what I'm going to do is take a copy of

136
00:05:37,189 --> 00:05:42,409
these. We're going to change this - instead

137
00:05:42,409 --> 00:05:44,449
of TasksContract here we're going to go

138
00:05:44,449 --> 00:05:46,549
with, in this next part,

139
00:05:46,549 --> 00:05:51,739
TimingsContract - then that'll be TIMINGS

140
00:05:51,739 --> 00:05:52,459
on the end there.

141
00:05:52,459 --> 00:05:55,789
And don't worry about these errors, I'll

142
00:05:55,789 --> 00:05:58,869
talk about those shortly. And in the

143
00:05:58,869 --> 00:06:02,959
string it's going to be TimingsContract

144
00:06:02,959 --> 00:06:06,079
TABLE_NAME, and instead of TASKS_ID it's

145
00:06:06,079 --> 00:06:10,639
going to be TIMINGS_ID. And

146
00:06:10,639 --> 00:06:13,699
we'll add one more group here, and this

147
00:06:13,699 --> 00:06:16,419
will be for the DurationsContract.

148
00:06:16,419 --> 00:06:21,429
So I'll come over to there, type Durations,
,
149

149
00:06:21,429 --> 00:06:23,599
Durations contract, and then on the end

150
00:06:23,599 --> 00:06:25,059
instead of TIMINGS it's going to be

151
00:06:25,059 --> 00:06:29,119
TASK_DURATIONS. And on the end

152
00:06:29,119 --> 00:06:30,409
here I'll just make that change - that's

153
00:06:30,409 --> 00:06:33,369
TASK_DURATIONS_ID.

154
00:06:33,369 --> 00:06:37,309
And then the actual string - instead of

155
00:06:37,309 --> 00:06:39,019
TimingsCcontract - is going to be

156
00:06:39,019 --> 00:06:42,970
DurationsContract.

157
00:06:42,970 --> 00:06:45,910
Okay, and again don't worry about the errors.

158
00:06:45,910 --> 00:06:48,340
I've included URIs for the timings

159
00:06:48,340 --> 00:06:50,470
and durations table that we'll be using

160
00:06:50,470 --> 00:06:52,630
later, because without them it's less

161
00:06:52,630 --> 00:06:55,450
obvious what this function's doing. Al

162
00:06:55,450 --> 00:06:57,070
right so when the function starts, it

163
00:06:57,070 --> 00:06:59,800
creates a new UriMatcher object and we

164
00:06:59,800 --> 00:07:02,620
can see that on line 38. The constructors

165
00:07:02,620 --> 00:07:05,200
parameter is a value to return if the

166
00:07:05,200 --> 00:07:07,720
route URI is matched. Now we don't

167
00:07:07,720 --> 00:07:10,030
want to re-match the route. A table name must be

168
00:07:10,030 --> 00:07:12,010
specified in the URL. Well that's why

169
00:07:12,010 --> 00:07:14,530
we're specifying NO_MATCH as

170
00:07:14,530 --> 00:07:18,190
the argument on line 38. Alright, so then

171
00:07:18,190 --> 00:07:20,050
we're adding the URIs that we want

172
00:07:20,050 --> 00:07:23,080
to match. So if the Tasks table is

173
00:07:23,080 --> 00:07:25,600
specified without an ID, the matcher will

174
00:07:25,600 --> 00:07:28,300
return 100, the value of our Tasks

175
00:07:28,300 --> 00:07:31,300
constant - that's the code on line 41. Now

176
00:07:31,300 --> 00:07:33,760
if an ID is also provided it'll return

177
00:07:33,760 --> 00:07:37,240
101 - the TASKS_ID constant, and

178
00:07:37,240 --> 00:07:40,180
that's the code on line 44. And for the

179
00:07:40,180 --> 00:07:44,350
Timings table we'll get 200 and 201, which

180
00:07:44,350 --> 00:07:46,180
is the value of TIMINGS and TIMINGS

181
00:07:46,180 --> 00:07:47,620
_ID - the constants that we've

182
00:07:47,620 --> 00:07:49,600
defined. Now we can scroll up and see

183
00:07:49,600 --> 00:07:52,150
those values again, the ones that we've

184
00:07:52,150 --> 00:07:53,590
defined up here earlier in the file, at

185
00:07:53,590 --> 00:07:57,190
the top of the file. Now just to be clear

186
00:07:57,190 --> 00:07:59,610
here, these numbers are totally arbitrary.

187
00:07:59,610 --> 00:08:01,810
We could have just set our constants to

188
00:08:01,810 --> 00:08:04,360
1, 2, 3 etc, which is what that Google

189
00:08:04,360 --> 00:08:06,550
example we just looked at, does. Now

190
00:08:06,550 --> 00:08:08,230
obviously we shouldn't use negative 1

191
00:08:08,230 --> 00:08:10,090
because that's the value of the Uri

192
00:08:10,090 --> 00:08:12,430
Matcher.NO_MATCH constant. And

193
00:08:12,430 --> 00:08:15,180
if you're wondering you can see that -

194
00:08:15,180 --> 00:08:17,530
I'll hover over it and click - you can see

195
00:08:17,530 --> 00:08:19,030
there that no matter is set defined to

196
00:08:19,030 --> 00:08:21,520
be negative 1. And if you haven't already

197
00:08:21,520 --> 00:08:23,290
done so, what I suggest you do is click

198
00:08:23,290 --> 00:08:25,030
on the documentation for one of these

199
00:08:25,030 --> 00:08:26,860
links. So I'm going to do the one for the

200
00:08:26,860 --> 00:08:29,500
first addURI, and it gives us some

201
00:08:29,500 --> 00:08:31,630
information. So you can see that the

202
00:08:31,630 --> 00:08:33,700
first parameter here's the authority, and

203
00:08:33,700 --> 00:08:35,830
the second one is the path that we want

204
00:08:35,830 --> 00:08:37,960
to match. So the path that we want to match

205
00:08:37,960 --> 00:08:40,450
can contain wild cards, either a hash

206
00:08:40,450 --> 00:08:43,360
or an asterisk. In this example we used

207
00:08:43,360 --> 00:08:45,280
a hash because we want to match any

208
00:08:45,280 --> 00:08:47,920
numeric ID. If you want to match any

209
00:08:47,920 --> 00:08:50,170
text, then you could use an asterisk

210
00:08:50,170 --> 00:08:51,880
which will match numbers as well as text.

211
00:08:51,880 --> 00:08:54,670
Now the use of the hash here is maybe

212
00:08:54,670 --> 00:08:56,850
unfortunate, as I mentioned in the

213
00:08:56,850 --> 00:08:58,139
previous video when were looking at

214
00:08:58,139 --> 00:09:01,050
URIs, because the hash character is used

215
00:09:01,050 --> 00:09:03,480
to separate a URI fragment in the

216
00:09:03,480 --> 00:09:05,790
specification that we looked at. So here

217
00:09:05,790 --> 00:09:07,500
though, the hash is something that the

218
00:09:07,500 --> 00:09:10,709
uriMatcher class interprets to mean any

219
00:09:10,709 --> 00:09:12,930
numeric value. And it's not used in the

220
00:09:12,930 --> 00:09:14,699
same way as the hash that separates a

221
00:09:14,699 --> 00:09:16,709
fragment from the rest of the URI that,

222
00:09:16,709 --> 00:09:20,160
again, we saw in the specification

223
00:09:20,160 --> 00:09:22,380
relating to URIs. Now there's no

224
00:09:22,380 --> 00:09:23,910
confusion as far as the class is

225
00:09:23,910 --> 00:09:25,860
concerned, because this second parameter

226
00:09:25,860 --> 00:09:29,190
is only matching the path part of the

227
00:09:29,190 --> 00:09:32,100
URI. So the third parameter is the code

228
00:09:32,100 --> 00:09:34,350
that we want the matcher to return, if it

229
00:09:34,350 --> 00:09:36,870
matches the URI. So go back to our code

230
00:09:36,870 --> 00:09:40,589
here; if the URI just refers to the Tasks

231
00:09:40,589 --> 00:09:43,199
table then the matcher would return 100,

232
00:09:43,199 --> 00:09:45,420
and if there's an ID on the end of the

233
00:09:45,420 --> 00:09:45,750
URI

234
00:09:45,750 --> 00:09:48,870
it'll return 101. And I've also included

235
00:09:48,870 --> 00:09:50,970
the code to match the timings and

236
00:09:50,970 --> 00:09:53,730
duration URIs, just so you can see

237
00:09:53,730 --> 00:09:55,230
how we get different values returned

238
00:09:55,230 --> 00:09:57,089
when dealing with the different

239
00:09:57,089 --> 00:09:59,040
URIs. Now at this point we haven't

240
00:09:59,040 --> 00:10:00,839
created the TimingsContract and

241
00:10:00,839 --> 00:10:03,449
DurationContract classes, so I'm going

242
00:10:03,449 --> 00:10:04,649
to comment out those lines just to

243
00:10:04,649 --> 00:10:07,019
remove the errors, but we'll uncomment

244
00:10:07,019 --> 00:10:08,819
this code once the classes have been

245
00:10:08,819 --> 00:10:13,920
written in later videos. So hopefully now,

246
00:10:13,920 --> 00:10:15,990
the reason for these constants that we

247
00:10:15,990 --> 00:10:17,939
defined at the top of the file should

248
00:10:17,939 --> 00:10:19,980
now be apparent. They're the values that

249
00:10:19,980 --> 00:10:22,410
the uriMatcher will be returning for us

250
00:10:22,410 --> 00:10:24,689
to ultimately match the URIs against.

251
00:10:24,689 --> 00:10:26,519
Alright so let's scroll down and look at the

252
00:10:26,519 --> 00:10:28,980
code, start implementing some code now.

253
00:10:28,980 --> 00:10:31,139
And we'll start by getting the onCreate

254
00:10:31,139 --> 00:10:33,389
method out of the way, then we can see

255
00:10:33,389 --> 00:10:36,240
how to use this your uriMatcher. Now

256
00:10:36,240 --> 00:10:38,430
although it's not important, I prefer to

257
00:10:38,430 --> 00:10:40,439
arrange these functions in a

258
00:10:40,439 --> 00:10:43,410
more logical order. So onCreate, to mind,

259
00:10:43,410 --> 00:10:46,139
should come first, and I expect to find

260
00:10:46,139 --> 00:10:48,569
it to the top of the class code. So I'm

261
00:10:48,569 --> 00:10:49,529
just going to move these functions

262
00:10:49,529 --> 00:10:50,939
around a little bit, so start with

263
00:10:50,939 --> 00:10:53,850
onCreate. So I'm just going to put that

264
00:10:53,850 --> 00:10:56,639
right at the top here, and the next one

265
00:10:56,639 --> 00:11:01,230
I'd expect to see there is getType - grab

266
00:11:01,230 --> 00:11:03,300
that as well -

267
00:11:03,300 --> 00:11:07,090
and put that below the onCreate. And the

268
00:11:07,090 --> 00:11:09,550
next one would be query, then we're going

269
00:11:09,550 --> 00:11:13,420
to move that. And then the other three;

270
00:11:13,420 --> 00:11:16,420
insert, update and delete, are fine in

271
00:11:16,420 --> 00:11:17,920
that order. And again, that's more a

272
00:11:17,920 --> 00:11:20,110
personal preference thing, but generally

273
00:11:20,110 --> 00:11:21,550
I would expect to be using things in

274
00:11:21,550 --> 00:11:23,590
that order, and therefore seeing the

275
00:11:23,590 --> 00:11:25,720
functions defined in that order as well.

276
00:11:25,720 --> 00:11:27,970
And what I'll also do is take the

277
00:11:27,970 --> 00:11:30,520
opportunity to remove the nullable type

278
00:11:30,520 --> 00:11:33,040
marker from all the Uri parameters. So let's

279
00:11:33,040 --> 00:11:39,820
go ahead and do that. Now these functions

280
00:11:39,820 --> 00:11:41,320
won't be called with a null Uri.

281
00:11:41,320 --> 00:11:44,230
If they are, something's gone wrong,

282
00:11:44,230 --> 00:11:45,940
and I'd much rather that was picked up

283
00:11:45,940 --> 00:11:47,890
by the compiler rather than having the

284
00:11:47,890 --> 00:11:50,230
app crash. And the same's actually true

285
00:11:50,230 --> 00:11:53,080
of the content value parameters - these

286
00:11:53,080 --> 00:11:55,570
ones here from the insert and update

287
00:11:55,570 --> 00:11:57,130
functions. There's really no point

288
00:11:57,130 --> 00:11:58,810
passing null for the values to insert,

289
00:11:58,810 --> 00:12:00,580
for example. It's just not going to work.

290
00:12:00,580 --> 00:12:02,980
So I'm going to remove the question mark

291
00:12:02,980 --> 00:12:03,370
there -

292
00:12:03,370 --> 00:12:05,860
the nullable type marker - from both the

293
00:12:05,860 --> 00:12:08,080
insert method for ContentValues, as well

294
00:12:08,080 --> 00:12:11,200
as the ContentValues for update. Alright,

295
00:12:11,200 --> 00:12:12,550
so getting back to our onCreate

296
00:12:12,550 --> 00:12:14,890
function, it's very simple - very, very

297
00:12:14,890 --> 00:12:16,990
simple. I'm not going to do anything in

298
00:12:16,990 --> 00:12:18,730
fact, in the code, but I'll start by

299
00:12:18,730 --> 00:12:22,450
deleting this TODO. Now we could create

300
00:12:22,450 --> 00:12:25,150
our database class in here, but as we've

301
00:12:25,150 --> 00:12:27,610
implemented it as a singleton, we'll just

302
00:12:27,610 --> 00:12:29,650
use the getInstance function whenever

303
00:12:29,650 --> 00:12:32,530
we need a database instance. But this on

304
00:12:32,530 --> 00:12:34,510
Create function has to be implemented

305
00:12:34,510 --> 00:12:37,270
though, and should return true. And just

306
00:12:37,270 --> 00:12:39,100
out of interest, it's worth demonstrating

307
00:12:39,100 --> 00:12:41,230
that we can't create instances of App

308
00:12:41,230 --> 00:12:43,630
Database, so I'll try and do that now. But

309
00:12:43,630 --> 00:12:45,540
I'll start with a log, Log.d

310
00:12:45,540 --> 00:12:50,740
parentheses TAG comma onCreate colon

311
00:12:50,740 --> 00:12:54,130
starts, and just to be consistent I'm going

312
00:12:54,130 --> 00:12:55,450
to add a colon up here - buildUri

313
00:12:55,450 --> 00:12:59,590
Matcher: starts as well, for the

314
00:12:59,590 --> 00:13:02,440
log. Alright, so I'm trying to create an

315
00:13:02,440 --> 00:13:05,230
instance of our AppDatabase; val app

316
00:13:05,230 --> 00:13:10,030
Database equals AppDatabase, and in

317
00:13:10,030 --> 00:13:14,170
parentheses context, and if I hover over

318
00:13:14,170 --> 00:13:15,730
it you can see, you "Cannot access init:

319
00:13:15,730 --> 00:13:16,390
it's

320
00:13:16,390 --> 00:13:18,490
private in AppDatabase". So that's

321
00:13:18,490 --> 00:13:20,410
actually what we want here: any attempt

322
00:13:20,410 --> 00:13:22,690
to create an AppDatabase instance will

323
00:13:22,690 --> 00:13:24,820
fail, and that's because we have to use

324
00:13:24,820 --> 00:13:27,040
the getInstance function. So I'm going

325
00:13:27,040 --> 00:13:28,510
to delete that line now just to remove

326
00:13:28,510 --> 00:13:34,920
that error, but what I will do is return true.

327
00:13:34,920 --> 00:13:36,760
Alright, so I mentioned that on

328
00:13:36,760 --> 00:13:39,640
Create's easy - it certainly was. I've added logging

329
00:13:39,640 --> 00:13:41,020
so that we can see the flow events in

330
00:13:41,020 --> 00:13:43,060
the logcat. But let's get back to using

331
00:13:43,060 --> 00:13:45,970
the uriMatcher - this time in the query

332
00:13:45,970 --> 00:13:49,540
function, which is the third implemented

333
00:13:49,540 --> 00:13:51,340
function. And I'm going to get back to

334
00:13:51,340 --> 00:13:54,040
getType, the getType function later. So

335
00:13:54,040 --> 00:13:55,960
the first parameter in the query, the

336
00:13:55,960 --> 00:13:58,210
query function here - and I'll delete the TO

337
00:13:58,210 --> 00:14:01,780
DO - so again, the first parameter is the

338
00:14:01,780 --> 00:14:04,000
URI. So we're going to start by

339
00:14:04,000 --> 00:14:06,070
using our uriMatcher to work out what

340
00:14:06,070 --> 00:14:08,290
kind of URI we've been given here.

341
00:14:08,290 --> 00:14:09,870
So I'm going to type Log.d

342
00:14:09,870 --> 00:14:13,090
parentheses TAG comma, as a comment

343
00:14:13,090 --> 00:14:17,470
query colon called with uri dollar

344
00:14:17,470 --> 00:14:19,690
uri, so I can see in logcat what it

345
00:14:19,690 --> 00:14:21,850
looks like. But the actual code will

346
00:14:21,850 --> 00:14:25,420
be val match equals uriMatcher dot

347
00:14:25,420 --> 00:14:28,270
match, in the parentheses, uri.

348
00:14:28,270 --> 00:14:30,160
Then we'll do a log for that as well; Log

349
00:14:30,160 --> 00:14:33,580
.d parentheses TAG comma, and it'll

350
00:14:33,580 --> 00:14:35,220
be query again :

351
00:14:35,220 --> 00:14:41,170
match is $match. Alright, at this

352
00:14:41,170 --> 00:14:43,030
point now we can use the value of match

353
00:14:43,030 --> 00:14:45,850
to decide which URI was passed into

354
00:14:45,850 --> 00:14:48,370
this query method, so that we know which

355
00:14:48,370 --> 00:14:51,010
table we should be using, for example. So

356
00:14:51,010 --> 00:14:52,450
the next thing we want to do, is use a

357
00:14:52,450 --> 00:14:55,030
queryBuilder to build the query that

358
00:14:55,030 --> 00:14:58,150
will be executed against the database. So

359
00:14:58,150 --> 00:15:00,280
to do that I'm going to type val query

360
00:15:00,280 --> 00:15:05,190
Builder colon and it's going to be SQLite

361
00:15:05,190 --> 00:15:09,820
QueryBuilder equals, and it's going to be

362
00:15:09,820 --> 00:15:13,180
SQLiteQueryBuilder. Now to get the

363
00:15:13,180 --> 00:15:14,770
documentation for the SQLiteQuery

364
00:15:14,770 --> 00:15:15,280
Builder,

365
00:15:15,280 --> 00:15:17,050
make sure you click on the type over here

366
00:15:17,050 --> 00:15:21,130
and not the constructor call. And you can

367
00:15:21,130 --> 00:15:22,750
see here that the documentation tells us

368
00:15:22,750 --> 00:15:25,630
that this is a convenience class that

369
00:15:25,630 --> 00:15:28,450
helps build SQL queries, to be sent to

370
00:15:28,450 --> 00:15:30,040
SQLite database

371
00:15:30,040 --> 00:15:32,949
subjects. So that's pretty useful. It's

372
00:15:32,949 --> 00:15:35,170
always easier to use a builtin object

373
00:15:35,170 --> 00:15:36,699
for building things like URIs or

374
00:15:36,699 --> 00:15:39,190
queries. The alternative is parsing and

375
00:15:39,190 --> 00:15:41,470
concatenating strings, which while not

376
00:15:41,470 --> 00:15:43,690
being terribly difficult, can quickly get

377
00:15:43,690 --> 00:15:46,329
messy. Alright to see how we use the

378
00:15:46,329 --> 00:15:48,040
SQLiteQueryBuilder, I'm going to

379
00:15:48,040 --> 00:15:49,480
paste in the rest of the code for this

380
00:15:49,480 --> 00:15:51,490
function, so that we can see what it does

381
00:15:51,490 --> 00:15:53,860
while I explain it. So let me just grab

382
00:15:53,860 --> 00:15:55,990
that code, and we'll actually get some

383
00:15:55,990 --> 00:15:57,910
errors here, and I'll deal with them once

384
00:15:57,910 --> 00:15:59,440
we've talked about what the code's doing.

385
00:15:59,440 --> 00:16:02,649
So I'm going to put this below the query

386
00:16:02,649 --> 00:16:05,470
Builder variable, the variable definition

387
00:16:05,470 --> 00:16:07,180
there. Now I'm also going to take the

388
00:16:07,180 --> 00:16:09,430
opportunity up here, to remove the

389
00:16:09,430 --> 00:16:13,990
redundant type declaration. I only added

390
00:16:13,990 --> 00:16:15,850
that so we had something to click on to

391
00:16:15,850 --> 00:16:18,040
see the documentation. So I mentioned

392
00:16:18,040 --> 00:16:19,569
we're going to get some errors. They're

393
00:16:19,569 --> 00:16:22,149
there mainly because, mostly because this

394
00:16:22,149 --> 00:16:23,470
includes the code for querying the

395
00:16:23,470 --> 00:16:25,750
timings and durations tables that we

396
00:16:25,750 --> 00:16:27,970
haven't created Contract classes for. And

397
00:16:27,970 --> 00:16:29,769
by the way, if you want to grab the code

398
00:16:29,769 --> 00:16:31,269
for this that I've just, the code for

399
00:16:31,269 --> 00:16:33,069
what I've just pasted in, it is in the

400
00:16:33,069 --> 00:16:34,870
resources section for this video if you

401
00:16:34,870 --> 00:16:36,209
want to go ahead and type that in.

402
00:16:36,209 --> 00:16:38,860
So again, I've added the code here for

403
00:16:38,860 --> 00:16:40,990
the timings and duration tables, because

404
00:16:40,990 --> 00:16:43,029
if there was only one table, it may not

405
00:16:43,029 --> 00:16:44,529
have been as obvious why we need to

406
00:16:44,529 --> 00:16:46,480
bother with the URI in the first

407
00:16:46,480 --> 00:16:48,550
place. I'm going to comment out the

408
00:16:48,550 --> 00:16:50,440
timings and durations code in a minute,

409
00:16:50,440 --> 00:16:52,510
but seeing all the code does make it

410
00:16:52,510 --> 00:16:54,550
easier, hopefully, to see why a Uri

411
00:16:54,550 --> 00:16:57,430
Matcher class is so useful. Alright so

412
00:16:57,430 --> 00:16:59,889
we're using a when here, a when statement to

413
00:16:59,889 --> 00:17:01,350
choose different blocks of code,

414
00:17:01,350 --> 00:17:04,000
depending on the result of matching the

415
00:17:04,000 --> 00:17:06,699
URI. If the URI just contained a

416
00:17:06,699 --> 00:17:08,770
table name, the basic query's pretty

417
00:17:08,770 --> 00:17:11,079
simple. It's just a SQL select with a

418
00:17:11,079 --> 00:17:13,150
TABLE_NAME. You can see that there - the

419
00:17:13,150 --> 00:17:16,329
code on line 74. And same for timings,

420
00:17:16,329 --> 00:17:21,549
line 82, and durations, line 90. So

421
00:17:21,549 --> 00:17:23,290
basically, when the URI matches TASKS,

422
00:17:23,290 --> 00:17:26,740
TIMINGS or TASKS_DURATIONS, we'll just

423
00:17:26,740 --> 00:17:29,320
call the setTables method to tell the

424
00:17:29,320 --> 00:17:31,240
queryBuilder which table we want to

425
00:17:31,240 --> 00:17:34,570
query. So the URI matches TASKS, TIMINGS

426
00:17:34,570 --> 00:17:36,700
or TASKS_DURATIONS. We're just

427
00:17:36,700 --> 00:17:39,370
using, we're just setting the tables

428
00:17:39,370 --> 00:17:42,520
property here, to tell the queryBuilder

429
00:17:42,520 --> 00:17:43,940
which table we want to use.

430
00:17:43,940 --> 00:17:45,620
And if we check the documentation there

431
00:17:45,620 --> 00:17:47,840
for that, you'll see that we can also

432
00:17:47,840 --> 00:17:50,870
specify more than one table and we can

433
00:17:50,870 --> 00:17:53,450
perform a join. So that's certainly one

434
00:17:53,450 --> 00:17:55,880
way of doing things, but another approach

435
00:17:55,880 --> 00:17:58,220
is to perform the join in the database

436
00:17:58,220 --> 00:18:01,010
using a view. So using a view made

437
00:18:01,010 --> 00:18:03,230
life easier in a SQL tutorial

438
00:18:03,230 --> 00:18:05,210
earlier in this course, and it also

439
00:18:05,210 --> 00:18:07,670
simplifies the code here in the provider.

440
00:18:07,670 --> 00:18:09,410
Now you can do it either way of course,

441
00:18:09,410 --> 00:18:11,570
but there's really no reason why the

442
00:18:11,570 --> 00:18:13,310
content provider should care about how

443
00:18:13,310 --> 00:18:16,240
the data's organized in the database.

444
00:18:16,240 --> 00:18:18,320
Implementation details like that really

445
00:18:18,320 --> 00:18:20,540
belong in the database, so the less our

446
00:18:20,540 --> 00:18:22,250
code relies on knowing about the

447
00:18:22,250 --> 00:18:24,500
implementation, the easier it is to

448
00:18:24,500 --> 00:18:27,260
change things in the future. This code

449
00:18:27,260 --> 00:18:29,240
though, as it stands, does have a

450
00:18:29,240 --> 00:18:31,700
potentially serious flaw though. Using

451
00:18:31,700 --> 00:18:34,010
queryBuilder.appendWhere, like

452
00:18:34,010 --> 00:18:35,980
we're using here, for example, on line 79,

453
00:18:35,980 --> 00:18:39,320
may introduce the potential for SQL

454
00:18:39,320 --> 00:18:41,330
injection attacks. In fact, if you've

455
00:18:41,330 --> 00:18:42,800
uploaded code like this to the Google

456
00:18:42,800 --> 00:18:44,960
Play Store, you'll get a warning and be

457
00:18:44,960 --> 00:18:47,180
told to fix it. So rather than using

458
00:18:47,180 --> 00:18:50,300
appendWhere, we'll use, the suggestion is to use

459
00:18:50,300 --> 00:18:52,130
appendWhereEscapeString, so I'm going

460
00:18:52,130 --> 00:18:55,790
to change that. And I'll take the

461
00:18:55,790 --> 00:19:03,260
opportunity to do that for all three. So

462
00:19:03,260 --> 00:19:05,630
let's call the, call up the documentation

463
00:19:05,630 --> 00:19:08,720
for that function. So the relevant part, and

464
00:19:08,720 --> 00:19:10,340
the difference from the appendWhere

465
00:19:10,340 --> 00:19:12,170
method that we're using, is this final

466
00:19:12,170 --> 00:19:14,210
sentence of the documentation, "it will be

467
00:19:14,210 --> 00:19:16,130
escaped to avoid SQL injection

468
00:19:16,130 --> 00:19:19,400
attacks". Now at the moment the lint

469
00:19:19,400 --> 00:19:20,810
checker doesn't pick up on this, and

470
00:19:20,810 --> 00:19:23,150
allows calls to appendWhere to get

471
00:19:23,150 --> 00:19:25,370
through with no warning. Until that

472
00:19:25,370 --> 00:19:27,710
changes be vigilant, and use the append

473
00:19:27,710 --> 00:19:30,050
WhereEscapeString function instead of

474
00:19:30,050 --> 00:19:32,510
appendWhere. Alright, so moving on

475
00:19:32,510 --> 00:19:36,230
now. If an ID is included in the URI,

476
00:19:36,230 --> 00:19:38,570
then the matcher will return TASK

477
00:19:38,570 --> 00:19:42,140
_ID, TIMINGS_ID or TASK

478
00:19:42,140 --> 00:19:45,140
_DURATIONS_ID. So in

479
00:19:45,140 --> 00:19:47,600
that case, we call the getId method of

480
00:19:47,600 --> 00:19:49,520
our Contracts class, and there's an example there

481
00:19:49,520 --> 00:19:52,400
on line 78, and that'll extract the ID

482
00:19:52,400 --> 00:19:55,700
for the URI, for us. Now this is another

483
00:19:55,700 --> 00:19:57,460
example of delegating responsibility

484
00:19:57,460 --> 00:20:00,520
where it belongs. Our Contract

485
00:20:00,520 --> 00:20:02,289
classes have intimate knowledge of the

486
00:20:02,289 --> 00:20:04,779
URIs, so it should be down to them to

487
00:20:04,779 --> 00:20:06,880
pass information out of the URIs.

488
00:20:06,880 --> 00:20:09,070
There's no need for the content provider

489
00:20:09,070 --> 00:20:11,140
to know that the ID appears in the

490
00:20:11,140 --> 00:20:13,210
second segment of the path - it just needs

491
00:20:13,210 --> 00:20:16,360
to get the ID from the URI. Now 

492
00:20:16,360 --> 00:20:18,130
we'll add that function to the

493
00:20:18,130 --> 00:20:20,860
Contract class in the next video. Now if

494
00:20:20,860 --> 00:20:22,779
there's an ID included in the URI, we'll

495
00:20:22,779 --> 00:20:25,570
call the queryBuilders appendWhere

496
00:20:25,570 --> 00:20:28,240
EscapeString function, and this adds a

497
00:20:28,240 --> 00:20:30,700
where clause to the query, and here the

498
00:20:30,700 --> 00:20:32,440
where clause will just be _ID

499
00:20:32,440 --> 00:20:34,809
equals whatever the actual ID value was.

500
00:20:34,809 --> 00:20:36,789
Alright, so I'm going to take this opportunity

501
00:20:36,789 --> 00:20:39,010
just to comment out the code now, for the

502
00:20:39,010 --> 00:20:45,700
tables that we haven't created yet. And

503
00:20:45,700 --> 00:20:47,140
in the next video we'll start work on

504
00:20:47,140 --> 00:20:50,020
getting that getId function in a Task

505
00:20:50,020 --> 00:20:52,179
contract class written, and make a few

506
00:20:52,179 --> 00:20:54,070
other changes. So I'll see you in the

507
00:20:54,070 --> 00:20:56,490
next video.

