1
00:00:04,730 --> 00:00:07,370
Alright, so moving on. When you open a

2
00:00:07,370 --> 00:00:10,250
HTTP connection, the server sends back

3
00:00:10,250 --> 00:00:13,070
a response code. So our code is going to

4
00:00:13,070 --> 00:00:14,540
get the, or does get the response

5
00:00:14,540 --> 00:00:16,849
code for the connection and logs it in

6
00:00:16,849 --> 00:00:19,400
the logcat, and that's this code here,

7
00:00:19,400 --> 00:00:22,669
on line 53. Now you may have seen HTTP

8
00:00:22,669 --> 00:00:24,500
response codes, when you try to visit a

9
00:00:24,500 --> 00:00:26,570
page that doesn't exist on a website, and

10
00:00:26,570 --> 00:00:28,759
you see 404 not found in your browser.

11
00:00:28,759 --> 00:00:32,570
Now 404 is the response code that a web

12
00:00:32,570 --> 00:00:34,700
server returns, if it can't find the page

13
00:00:34,700 --> 00:00:37,430
that was requested. Now if you want to

14
00:00:37,430 --> 00:00:39,500
check the HTTP response codes, then

15
00:00:39,500 --> 00:00:42,380
google HTTP response codes. We'll just do

16
00:00:42,380 --> 00:00:45,079
that quickly now. You get a lot of

17
00:00:45,079 --> 00:00:54,320
information - HTTP response codes. And you

18
00:00:54,320 --> 00:00:55,970
can see here, we've got one from

19
00:00:55,970 --> 00:00:58,880
Wikipedia - List of HTTP response codes,

20
00:00:58,880 --> 00:01:01,430
but there's also another one, and this

21
00:01:01,430 --> 00:01:03,890
one here - Status Code definitions. That's

22
00:01:03,890 --> 00:01:06,380
actually the definitive reference, so I'm gonna

23
00:01:06,380 --> 00:01:07,909
click on that just briefly and open it,

24
00:01:07,909 --> 00:01:09,319
although I don't expect you to memorize it.

25
00:01:09,319 --> 00:01:11,929
But with that said, the Wikipedia entry,

26
00:01:11,929 --> 00:01:14,439
which I'll just go back to now,

27
00:01:14,439 --> 00:01:16,549
that's more accurate and a bit more

28
00:01:16,549 --> 00:01:19,189
readable. So I'd suggest that that would

29
00:01:19,189 --> 00:01:20,479
be a good place for you to start, and we

30
00:01:20,479 --> 00:01:22,310
can see if we just scroll down here, the

31
00:01:22,310 --> 00:01:24,920
various areas; 404, The requested resource

32
00:01:24,920 --> 00:01:27,170
couldn't be found, or could not be found

33
00:01:27,170 --> 00:01:28,539
but maybe available in the future.

34
00:01:28,539 --> 00:01:30,590
Subsequent requests by the client are

35
00:01:30,590 --> 00:01:32,990
permissible. So basically, going back to

36
00:01:32,990 --> 00:01:35,959
our code. The code itself creates an

37
00:01:35,959 --> 00:01:38,209
InputStream - that's this line here, line

38
00:01:38,209 --> 00:01:41,569
56 - and then uses it to create an Input

39
00:01:41,569 --> 00:01:44,270
StreamReader on the next line. Now the

40
00:01:44,270 --> 00:01:45,770
InputStreamReader is then used to

41
00:01:45,770 --> 00:01:49,999
create a BufferedReader on line 58. Now

42
00:01:49,999 --> 00:01:51,979
this can look a bit horrible, but these

43
00:01:51,979 --> 00:01:54,409
IO classes have been designed to work

44
00:01:54,409 --> 00:01:56,329
together in this way. And they're part of

45
00:01:56,329 --> 00:01:58,490
the Java.io package, so this is

46
00:01:58,490 --> 00:02:01,840
standard Java, not Android specific code.

47
00:02:01,840 --> 00:02:03,829
Now we're going to be using a lot of

48
00:02:03,829 --> 00:02:06,189
Java classes from our Kotlin code,

49
00:02:06,189 --> 00:02:08,360
especially as most of Android is still

50
00:02:08,360 --> 00:02:10,940
written in Java. Now reading the code

51
00:02:10,940 --> 00:02:13,760
upwards, the BufferedReader buffers the

52
00:02:13,760 --> 00:02:16,040
InputStreamReader, and it'll be the

53
00:02:16,040 --> 00:02:17,480
BufferedReader that we'll use to

54
00:02:17,480 --> 00:02:18,560
actually read the

55
00:02:18,560 --> 00:02:21,860
XML. Now the InputStreamReader uses an

56
00:02:21,860 --> 00:02:24,170
InputStream object as the source of its

57
00:02:24,170 --> 00:02:26,780
data, and the InputStream is created

58
00:02:26,780 --> 00:02:29,959
from our open HTTP connection. Now you

59
00:02:29,959 --> 00:02:31,700
wouldn't normally see the code written

60
00:02:31,700 --> 00:02:33,950
like that. Because these classes are

61
00:02:33,950 --> 00:02:36,110
designed to work together, it's more

62
00:02:36,110 --> 00:02:37,970
usual to chain the method calls together.

63
00:02:37,970 --> 00:02:40,069
So what I'm going to do is make a change

64
00:02:40,069 --> 00:02:41,660
so that you can see the more usual way,

65
00:02:41,660 --> 00:02:44,180
and comment out the

66
00:02:44,180 --> 00:02:46,430
current code so that you can compare it.

67
00:02:46,430 --> 00:02:49,120
So I'm going to come up here before the,

68
00:02:49,120 --> 00:02:51,830
these three down here; inputStream,

69
00:02:51,830 --> 00:02:53,750
inputStreamreader and reader, and I'm

70
00:02:53,750 --> 00:02:57,080
going to comment those out. And 

71
00:02:57,080 --> 00:02:58,160
instead, I'm going to replace that with one

72
00:02:58,160 --> 00:03:02,440
line, which will be val reader equals

73
00:03:02,440 --> 00:03:07,269
BufferedReader, then InputStream,

74
00:03:07,269 --> 00:03:11,209
parentheses InputStreamreader, then

75
00:03:11,209 --> 00:03:15,220
another set of parentheses, connection

76
00:03:15,220 --> 00:03:18,739
dot InputStream, and close the two

77
00:03:18,739 --> 00:03:20,049
parentheses there.

78
00:03:20,049 --> 00:03:23,150
So the previous three lines of code can

79
00:03:23,150 --> 00:03:25,250
be replaced with a single line that does

80
00:03:25,250 --> 00:03:26,720
exactly the same thing.

81
00:03:26,720 --> 00:03:29,000
Now one other neat thing about the way

82
00:03:29,000 --> 00:03:31,010
that these i/o classes are designed to

83
00:03:31,010 --> 00:03:33,079
work together, is that closing the

84
00:03:33,079 --> 00:03:35,390
BufferedReader will automatically close

85
00:03:35,390 --> 00:03:37,489
the InputStreamreader, and when the Input

86
00:03:37,489 --> 00:03:39,380
StreamReader closes, it'll close its

87
00:03:39,380 --> 00:03:41,630
InputStream. And we'll see that working

88
00:03:41,630 --> 00:03:42,890
later when we add the code to close

89
00:03:42,890 --> 00:03:45,709
things down. Now if you need to, you can

90
00:03:45,709 --> 00:03:47,150
find out more information about the

91
00:03:47,150 --> 00:03:49,310
BufferedReader for Android, so I'm going

92
00:03:49,310 --> 00:03:51,769
to take a copy of a link and paste it

93
00:03:51,769 --> 00:03:59,660
into the browser. And as usual, as always,

94
00:03:59,660 --> 00:04:01,100
the links are in the resources section

95
00:04:01,100 --> 00:04:03,680
for the video. So that's the Android

96
00:04:03,680 --> 00:04:05,090
documentation that I've pointed you to,

97
00:04:05,090 --> 00:04:07,519
but the Bufferedreader is a Java class,

98
00:04:07,519 --> 00:04:09,350
so you'll also find the Oracle

99
00:04:09,350 --> 00:04:11,389
documentation on the java.io package

100
00:04:11,389 --> 00:04:13,310
useful, if you want to find out more

101
00:04:13,310 --> 00:04:15,530
information. Now there's one more

102
00:04:15,530 --> 00:04:17,120
exception that we should deal with.

103
00:04:17,120 --> 00:04:19,570
Now this one's necessary because Android

104
00:04:19,570 --> 00:04:21,709
requires an app to be granted

105
00:04:21,709 --> 00:04:24,139
permissions to do certain things, such as

106
00:04:24,139 --> 00:04:26,510
accessing the Internet. Now Google

107
00:04:26,510 --> 00:04:28,220
changed the way that permissions worked

108
00:04:28,220 --> 00:04:30,860
in Android Marshmallow, so to deal with

109
00:04:30,860 --> 00:04:32,630
them properly isn't always just a trivial

110
00:04:32,630 --> 00:04:35,240
change to the manifest. Now I'm going to

111
00:04:35,240 --> 00:04:37,070
deal with the permissions, and also cover

112
00:04:37,070 --> 00:04:39,620
catching the security exception in a

113
00:04:39,620 --> 00:04:40,430
later video.

114
00:04:40,430 --> 00:04:42,560
So we've now got a connection to the

115
00:04:42,560 --> 00:04:44,990
Internet, and we've set up the reader so

116
00:04:44,990 --> 00:04:47,810
we can read in the download at XML. All

117
00:04:47,810 --> 00:04:49,310
we have to do at this point, is read the

118
00:04:49,310 --> 00:04:51,620
data in and append it to our String

119
00:04:51,620 --> 00:04:53,750
Builder until there's no more data left

120
00:04:53,750 --> 00:04:56,480
to read. Now a BuffereReader actually

121
00:04:56,480 --> 00:04:59,780
reads characters, not strings, so we need

122
00:04:59,780 --> 00:05:01,910
to set up a character array that's going

123
00:05:01,910 --> 00:05:03,320
to be filled with characters from the

124
00:05:03,320 --> 00:05:05,330
buffer. So I'm going to add the code to

125
00:05:05,330 --> 00:05:07,640
read the data inside the try block, after

126
00:05:07,640 --> 00:05:12,110
line 59, down here. So I'm going to start

127
00:05:12,110 --> 00:05:18,620
with val input buffer equals Char

128
00:05:18,620 --> 00:05:24,650
Array, 500 in parentheses. Then we're

129
00:05:24,650 --> 00:05:29,770
going to do var charsRead equals 0.

130
00:05:29,770 --> 00:05:33,640
Then we're gonna do while parentheses

131
00:05:33,640 --> 00:05:37,630
CharsRead greater than equal to 0,

132
00:05:37,630 --> 00:05:39,770
closing parentheses and open a code

133
00:05:39,770 --> 00:05:44,120
block. Then we're gonna do charsRead equals

134
00:05:44,120 --> 00:05:50,810
reader.read inputBuffer. And on the

135
00:05:50,810 --> 00:05:53,540
next line, if charsRead is greater

136
00:05:53,540 --> 00:05:59,980
than 0, code block xmlResult.append

137
00:05:59,980 --> 00:06:05,480
String parentheses inputBuffer comma

138
00:06:05,480 --> 00:06:10,040
space 0 comma space charsRead. I'm

139
00:06:10,040 --> 00:06:11,420
putting an extra space between all these

140
00:06:11,420 --> 00:06:14,180
variables, just for ease of

141
00:06:14,180 --> 00:06:15,590
readability, but you don't necessarily

142
00:06:15,590 --> 00:06:18,020
have to do that. Now I made a mistake

143
00:06:18,020 --> 00:06:19,550
there - while charsRead is less than

144
00:06:19,550 --> 00:06:21,260
equal to 0 should, of course, be greater

145
00:06:21,260 --> 00:06:23,300
than equal to 0, because you want to keep

146
00:06:23,300 --> 00:06:24,830
testing and reading data while there's

147
00:06:24,830 --> 00:06:27,080
some data there. So basically, I've

148
00:06:27,080 --> 00:06:29,480
created the inputBuffer character array,

149
00:06:29,480 --> 00:06:33,530
here on line 61, to store 500

150
00:06:33,530 --> 00:06:35,180
characters. Now that number's a bit

151
00:06:35,180 --> 00:06:37,550
arbitrary, and if you expected a large

152
00:06:37,550 --> 00:06:39,350
download, you may be able to improve

153
00:06:39,350 --> 00:06:42,080
performance by increasing it. The size of

154
00:06:42,080 --> 00:06:43,490
the buffer used internally by the

155
00:06:43,490 --> 00:06:45,260
BufferedReader on Android is currently

156
00:06:45,260 --> 00:06:46,129
8192

157
00:06:46,129 --> 00:06:49,909
bytes, which is okay, but if we were

158
00:06:49,909 --> 00:06:51,649
reading from disk than a larger value

159
00:06:51,649 --> 00:06:54,529
would be a good idea. TCP packets are

160
00:06:54,529 --> 00:06:57,019
typically much smaller than 8k, so we

161
00:06:57,019 --> 00:06:58,879
read 500 characters at a time and let

162
00:06:58,879 --> 00:07:00,860
the Bufferedreader deal with getting the

163
00:07:00,860 --> 00:07:02,659
data off the inputStream and holding it

164
00:07:02,659 --> 00:07:05,139
in the buffer for us. Now the while loop,

165
00:07:05,139 --> 00:07:09,289
which was starting on line 63, that'll

166
00:07:09,289 --> 00:07:10,909
keep going around until the end of the

167
00:07:10,909 --> 00:07:13,369
inputstream's reached. Now if the

168
00:07:13,369 --> 00:07:15,830
Bufferedreader's read function returns a

169
00:07:15,830 --> 00:07:18,259
value less than zero, then that signals

170
00:07:18,259 --> 00:07:20,419
the end of the stream of data, and the

171
00:07:20,419 --> 00:07:22,550
loop terminates. So that's why we've got

172
00:07:22,550 --> 00:07:26,029
the condition on line 63; charsRead

173
00:07:26,029 --> 00:07:28,759
greater than equal to zero. We're only going to

174
00:07:28,759 --> 00:07:31,399
loop as long as there is data available. Once

175
00:07:31,399 --> 00:07:32,659
there's no more data in the input

176
00:07:32,659 --> 00:07:34,909
Stream, we're going to stop, otherwise

177
00:07:34,909 --> 00:07:36,800
charsRead will hold a count of the

178
00:07:36,800 --> 00:07:38,329
number of characters read from the

179
00:07:38,329 --> 00:07:40,879
stream. Now it is possible for this to be

180
00:07:40,879 --> 00:07:42,860
zero, but just because there was nothing

181
00:07:42,860 --> 00:07:45,259
currently available to read, that doesn't

182
00:07:45,259 --> 00:07:47,139
mean more data won't come down later.

183
00:07:47,139 --> 00:07:49,909
So we don't stop looping if nothing was

184
00:07:49,909 --> 00:07:52,129
read, but there's also no point appending

185
00:07:52,129 --> 00:07:54,800
nothing to xmlResult. So the code checks

186
00:07:54,800 --> 00:07:56,899
that charsRead is greater than zero -

187
00:07:56,899 --> 00:07:59,599
doing this on line 65 - before

188
00:07:59,599 --> 00:08:01,599
appending the characters to the result.

189
00:08:01,599 --> 00:08:04,879
Now technically, that check for chars

190
00:08:04,879 --> 00:08:07,249
Read greater than zero is redundant, with

191
00:08:07,249 --> 00:08:09,469
the Java classes we're using. If there's

192
00:08:09,469 --> 00:08:11,269
no data available, but we haven't yet

193
00:08:11,269 --> 00:08:13,879
read it all, the reader will block - what

194
00:08:13,879 --> 00:08:15,409
that means, it'll wait until there is

195
00:08:15,409 --> 00:08:17,990
more data available. So with these

196
00:08:17,990 --> 00:08:20,269
particular classes, we'll never get zero

197
00:08:20,269 --> 00:08:22,879
bytes returned. However, not all readers

198
00:08:22,879 --> 00:08:25,429
work the same way, and 0 may be returned,

199
00:08:25,429 --> 00:08:27,349
even though the end of the stream hasn't

200
00:08:27,349 --> 00:08:29,119
been reached. So I've coded this

201
00:08:29,119 --> 00:08:31,339
defensively, so that we don't stop

202
00:08:31,339 --> 00:08:32,809
reading just because there's no data

203
00:08:32,809 --> 00:08:35,630
currently available. More may turn up a

204
00:08:35,630 --> 00:08:38,208
few milliseconds afterwards. Now, although

205
00:08:38,208 --> 00:08:39,919
we're writing this code for a particular

206
00:08:39,919 --> 00:08:42,559
purpose - in this case, to download an RSS

207
00:08:42,559 --> 00:08:44,569
feed from Apple - you may actually want to

208
00:08:44,569 --> 00:08:46,459
re-use it for different purposes. So

209
00:08:46,459 --> 00:08:48,170
that's why I've catered for the

210
00:08:48,170 --> 00:08:50,180
possibility that there's nothing yet

211
00:08:50,180 --> 00:08:52,850
available to read. And note also, that we

212
00:08:52,850 --> 00:08:54,889
don't try to copy 500 characters from

213
00:08:54,889 --> 00:08:57,110
the inputBuffer - this is the code on

214
00:08:57,110 --> 00:08:59,260
line 66 - and that's

215
00:08:59,260 --> 00:09:01,150
because there's no guarantee that 500

216
00:09:01,150 --> 00:09:03,640
characters were available. Instead, we're

217
00:09:03,640 --> 00:09:04,960
only copying the number of characters

218
00:09:04,960 --> 00:09:07,690
read, which is the value of charsRead,

219
00:09:07,690 --> 00:09:10,000
or the charsRead variable.

220
00:09:10,000 --> 00:09:12,760
So each time around the loop, more

221
00:09:12,760 --> 00:09:14,560
characters will be appended to the xml

222
00:09:14,560 --> 00:09:16,780
Result, until there's nothing left to

223
00:09:16,780 --> 00:09:19,060
read. When the end of the inputSteam's

224
00:09:19,060 --> 00:09:21,610
been reached, the loop terminates and we

225
00:09:21,610 --> 00:09:24,370
close the BufferedReader. As I mentioned

226
00:09:24,370 --> 00:09:26,020
earlier, that will automatically close

227
00:09:26,020 --> 00:09:28,030
the InputStreamReader and the input

228
00:09:28,030 --> 00:09:30,400
Stream. And we can check the source for

229
00:09:30,400 --> 00:09:32,380
the BufferedReader's close method, by

230
00:09:32,380 --> 00:09:34,870
holding down the command key on a Mac or

231
00:09:34,870 --> 00:09:37,960
Ctrl key on a PC or Linux machine. So we

232
00:09:37,960 --> 00:09:42,220
click BufferedReader first, to open that,

233
00:09:42,220 --> 00:09:44,290
and if we come down and have a look for

234
00:09:44,290 --> 00:09:48,760
the close method. Now unfortunately, I'm

235
00:09:48,760 --> 00:09:50,380
recording this video before Google have

236
00:09:50,380 --> 00:09:53,230
made the API 26 source available, but

237
00:09:53,230 --> 00:09:54,550
by the time you watch this, you should be

238
00:09:54,550 --> 00:09:57,040
able to jump into the source. Until then,

239
00:09:57,040 --> 00:09:58,540
I've got a couple of slides that I want

240
00:09:58,540 --> 00:09:59,800
to show you, of what it would look like

241
00:09:59,800 --> 00:10:03,550
with the current source code. So this is

242
00:10:03,550 --> 00:10:04,840
the source, now on screen, for the

243
00:10:04,840 --> 00:10:06,580
BufferedReader, showing it's close

244
00:10:06,580 --> 00:10:08,620
method. So the comment does state that it

245
00:10:08,620 --> 00:10:10,360
closes the source reader and we can

246
00:10:10,360 --> 00:10:12,430
see the call to in.close in that

247
00:10:12,430 --> 00:10:15,520
method. Now the reader variable, in, is

248
00:10:15,520 --> 00:10:18,040
actually of type Reader. But we're

249
00:10:18,040 --> 00:10:20,440
using an InputStreamReader, so we can't

250
00:10:20,440 --> 00:10:22,090
just click on the in.close method

251
00:10:22,090 --> 00:10:24,160
here to check the source. We can go back

252
00:10:24,160 --> 00:10:25,900
to our source and command click or

253
00:10:25,900 --> 00:10:27,430
control-click on the InputStreamReader

254
00:10:27,430 --> 00:10:29,770
class, to see the source for that and

255
00:10:29,770 --> 00:10:32,020
then search for the close method - well we

256
00:10:32,020 --> 00:10:33,310
could do that if we had the source code.

257
00:10:33,310 --> 00:10:35,050
But instead, what I'm gonna do is show

258
00:10:35,050 --> 00:10:36,580
you, on the next slide, what that would

259
00:10:36,580 --> 00:10:39,130
end up being. So once again, looking at

260
00:10:39,130 --> 00:10:41,140
that code you can see that it closes the

261
00:10:41,140 --> 00:10:43,720
source InputStream. Alright, so let's

262
00:10:43,720 --> 00:10:47,120
move back to Android Studio.

263
00:10:47,120 --> 00:10:49,490
So as you can see, there's no one need to

264
00:10:49,490 --> 00:10:51,410
close all the i/o objects that we've

265
00:10:51,410 --> 00:10:53,779
used - closing the BufferedReader takes

266
00:10:53,779 --> 00:10:56,540
care of everything else for us. So let's

267
00:10:56,540 --> 00:10:58,100
go ahead and add the code for that. So if

268
00:10:58,100 --> 00:11:01,519
I come down here and add reader dot

269
00:11:01,519 --> 00:11:04,819
close, and that's the method to close the

270
00:11:04,819 --> 00:11:07,279
BufferedReader. Alright, so the last

271
00:11:07,279 --> 00:11:08,930
thing we need to get our download XML

272
00:11:08,930 --> 00:11:11,319
function to do, is to return the results.

273
00:11:11,319 --> 00:11:13,579
Now if everything went well,

274
00:11:13,579 --> 00:11:16,459
we can just return the xmlResult, but

275
00:11:16,459 --> 00:11:18,470
as it's a StringBuilder, we need to

276
00:11:18,470 --> 00:11:21,019
first convert it to a string. And I'm

277
00:11:21,019 --> 00:11:22,459
also going to log the number of bytes

278
00:11:22,459 --> 00:11:23,930
received from information and to help

279
00:11:23,930 --> 00:11:26,629
debugging, if things go wrong. So below

280
00:11:26,629 --> 00:11:29,569
that reader.close method call, let's

281
00:11:29,569 --> 00:11:34,550
add Log.d, and in parentheses, TAG, and

282
00:11:34,550 --> 00:11:37,879
then double quotes, Received dollar sign

283
00:11:37,879 --> 00:11:41,990
and left and right curly braces, xmlResult

284
00:11:41,990 --> 00:11:45,680
dot length. Then outside of the right

285
00:11:45,680 --> 00:11:51,139
curly brace, the word bytes, and then we

286
00:11:51,139 --> 00:11:57,699
go to return xmlResult.toString.

287
00:11:57,699 --> 00:11:59,540
Okay, so you can see that we've actually

288
00:11:59,540 --> 00:12:02,240
done that now. Now, if there are any errors

289
00:12:02,240 --> 00:12:03,620
caught in our catch block, we should

290
00:12:03,620 --> 00:12:06,379
return an empty string. So we saw the

291
00:12:06,379 --> 00:12:08,240
doInBackground function check for an

292
00:12:08,240 --> 00:12:10,309
empty string after calling downloadXML.

293
00:12:10,309 --> 00:12:12,730
So what we're going to do is, down here,

294
00:12:12,730 --> 00:12:14,360
bearing in mind that we've already

295
00:12:14,360 --> 00:12:16,370
returned the results if we found some,

296
00:12:16,370 --> 00:12:19,100
but after the closing catch block, we're

297
00:12:19,100 --> 00:12:21,379
going to return an empty string - two

298
00:12:21,379 --> 00:12:23,809
double quotes. So basically, the

299
00:12:23,809 --> 00:12:27,670
comment we'll add there, It it gets to here,

300
00:12:27,670 --> 00:12:30,429
there's been a problem.

301
00:12:30,429 --> 00:12:34,189
Return an empty string. So that just tells

302
00:12:34,189 --> 00:12:36,740
us there was some error that has been

303
00:12:36,740 --> 00:12:39,679
caught by our try catch blocks, and we're

304
00:12:39,679 --> 00:12:40,850
going to return an empty string for that

305
00:12:40,850 --> 00:12:44,360
reason. What we're doing now is, we'll try

306
00:12:44,360 --> 00:12:45,949
giving this a bit of a test run, so let's

307
00:12:45,949 --> 00:12:52,090
go ahead and do that.

308
00:12:52,090 --> 00:12:54,470
Now, we've actually got an error here, and

309
00:12:54,470 --> 00:12:56,990
the error is Unresolved reference:

310
00:12:56,990 --> 00:12:59,360
downloadXML. So at first glance, you might

311
00:12:59,360 --> 00:13:00,620
be looking at that and wondering, Well,

312
00:13:00,620 --> 00:13:02,660
clearly I've got the names correctly

313
00:13:02,660 --> 00:13:04,970
entered here. Why do we have this error?

314
00:13:04,970 --> 00:13:08,000
Well the reason is that we need to have

315
00:13:08,000 --> 00:13:10,760
this private function inside our private

316
00:13:10,760 --> 00:13:12,590
class - our DownloadData class - and I've

317
00:13:12,590 --> 00:13:14,570
actually got it outside of it. So I'm

318
00:13:14,570 --> 00:13:16,240
going to take a copy of that entire

319
00:13:16,240 --> 00:13:20,450
function. I'm going to do a cut to take

320
00:13:20,450 --> 00:13:22,760
it out of its current location, and I'm

321
00:13:22,760 --> 00:13:24,080
going to come up here now, make sure

322
00:13:24,080 --> 00:13:26,600
that it's now in our companion object - our

323
00:13:26,600 --> 00:13:29,150
private class for DownloadData - and we

324
00:13:29,150 --> 00:13:31,220
need to paste it in our private class. We

325
00:13:31,220 --> 00:13:33,710
need to come down here, after the doing

326
00:13:33,710 --> 00:13:35,360
Background method and paste it down

327
00:13:35,360 --> 00:13:38,000
there, and once we do that, we should find

328
00:13:38,000 --> 00:13:41,180
the error disappears. The private function

329
00:13:41,180 --> 00:13:43,760
downloadXML there is okay, and we

330
00:13:43,760 --> 00:13:45,440
haven't got any other errors showing. So

331
00:13:45,440 --> 00:13:46,820
we should now be able to try running

332
00:13:46,820 --> 00:13:48,740
this again, so I'm just going to - well

333
00:13:48,740 --> 00:13:50,750
actually, I'll leave, I'll close this down

334
00:13:50,750 --> 00:13:52,430
because we're going to open logcat, and

335
00:13:52,430 --> 00:13:57,110
we'll try running it again. And we should

336
00:13:57,110 --> 00:13:59,090
find, this time, it'll work, but we are

337
00:13:59,090 --> 00:14:03,080
going to get errors the first time. Al

338
00:14:03,080 --> 00:14:04,970
right, so we've got the app working, but if

339
00:14:04,970 --> 00:14:07,120
we open logcat and take a bit of a look,

340
00:14:07,120 --> 00:14:10,010
though we've still got the filter set, so

341
00:14:10,010 --> 00:14:11,930
that's a good thing at the moment. So as

342
00:14:11,930 --> 00:14:13,070
I mention, we're gonna get errors and we

343
00:14:13,070 --> 00:14:14,480
have got errors, and that's a good thing

344
00:14:14,480 --> 00:14:16,640
at the moment, because we're getting a

345
00:14:16,640 --> 00:14:18,640
chance to test the catch blocks in

346
00:14:18,640 --> 00:14:21,710
downloadXML. So you can see we've got

347
00:14:21,710 --> 00:14:24,500
the onCreate called, onCreate: done, doing

348
00:14:24,500 --> 00:14:26,600
Background: starting with a URL goes here.

349
00:14:26,600 --> 00:14:28,250
But then we've got this message here,

350
00:14:28,250 --> 00:14:31,430
downloadXML: Invalid URL no protocol: URL

351
00:14:31,430 --> 00:14:34,130
goes here, Error downloading and onPost

352
00:14:34,130 --> 00:14:37,250
Execute: parameter is, an empty string. So

353
00:14:37,250 --> 00:14:38,390
the error we're getting - Error

354
00:14:38,390 --> 00:14:41,150
downloading - if we come back and have a

355
00:14:41,150 --> 00:14:43,310
look at our code. Well the one

356
00:14:43,310 --> 00:14:45,470
above it is Invalid URL no protocol:

357
00:14:45,470 --> 00:14:47,720
that relates to the MalformedURL

358
00:14:47,720 --> 00:14:48,920
Exception - that's the error message that

359
00:14:48,920 --> 00:14:53,270
is being generated on line 73. And as

360
00:14:53,270 --> 00:14:54,820
a result of that, the doingBackground

361
00:14:54,820 --> 00:14:57,350
function is also reporting error

362
00:14:57,350 --> 00:14:59,110
downloading, for the fact that

363
00:14:59,110 --> 00:15:01,910
because it failed, ultimately, because of

364
00:15:01,910 --> 00:15:04,790
that invalid URL. So let's actually go

365
00:15:04,790 --> 00:15:05,630
back

366
00:15:05,630 --> 00:15:08,540
and provide the correct URL to the Apple

367
00:15:08,540 --> 00:15:11,720
10 top feed of free apps. I'm going

368
00:15:11,720 --> 00:15:14,269
to go back to the browser. I'm gonna go

369
00:15:14,269 --> 00:15:17,630
back. go back here. I'm gonna go back

370
00:15:17,630 --> 00:15:20,060
until I find the link, which was several

371
00:15:20,060 --> 00:15:22,459
videos ago. There it is there. You can go

372
00:15:22,459 --> 00:15:24,889
back to the original Apple link if you

373
00:15:24,889 --> 00:15:26,149
haven't got it on your browser, which I had

374
00:15:26,149 --> 00:15:27,769
in the previous video, and I'll also put

375
00:15:27,769 --> 00:15:30,110
this link in the resources section. I've

376
00:15:30,110 --> 00:15:32,540
taken a copy of that back to Android

377
00:15:32,540 --> 00:15:34,850
Studio, and we're gonna go back up now to

378
00:15:34,850 --> 00:15:38,540
find the dot execute method call, and

379
00:15:38,540 --> 00:15:40,819
send the right arguments. At the moment,

380
00:15:40,819 --> 00:15:43,279
it's here at downloadData.execute.

381
00:15:43,279 --> 00:15:46,250
Let's paste in the correct value

382
00:15:46,250 --> 00:15:48,380
there, which is that URL.

383
00:15:48,380 --> 00:15:50,089
So basically, that's in the onCreate

384
00:15:50,089 --> 00:15:52,699
function, which is the DownloadData

385
00:15:52,699 --> 00:15:54,920
dot execute, which invokes or starts

386
00:15:54,920 --> 00:15:58,279
the AsyncTask. So the onCreate

387
00:15:58,279 --> 00:15:59,930
method creates a new instance of the

388
00:15:59,930 --> 00:16:02,449
DownloadData class, then calls it's dot

389
00:16:02,449 --> 00:16:05,240
execute method. And that causes Android

390
00:16:05,240 --> 00:16:07,250
to call the doinBackground method on

391
00:16:07,250 --> 00:16:08,839
a separate thread and passes this

392
00:16:08,839 --> 00:16:11,120
parameter that we've just pasted into

393
00:16:11,120 --> 00:16:13,519
the execute function call, into the doin

394
00:16:13,519 --> 00:16:16,310
Background function. Now I haven't given

395
00:16:16,310 --> 00:16:17,569
the app permission to access the

396
00:16:17,569 --> 00:16:19,579
internet yet, so if I run it now, we

397
00:16:19,579 --> 00:16:21,500
should see the security exception being

398
00:16:21,500 --> 00:16:23,569
thrown, and it's caught because we've

399
00:16:23,569 --> 00:16:24,980
finished our catch blocks by catching

400
00:16:24,980 --> 00:16:27,199
any exception that hasn't been listed

401
00:16:27,199 --> 00:16:30,259
earlier. But before I run it again, I'm

402
00:16:30,259 --> 00:16:31,819
going to clear the logcat by clicking on

403
00:16:31,819 --> 00:16:33,470
this trashcan over here onto the left

404
00:16:33,470 --> 00:16:36,560
of the logcat pane, just so it's easier to

405
00:16:36,560 --> 00:16:38,269
find the results from this run, rather

406
00:16:38,269 --> 00:16:39,649
than building up a huge log and having

407
00:16:39,649 --> 00:16:41,990
to scroll. In general, it's a good idea to

408
00:16:41,990 --> 00:16:44,360
clear the logcat before testing your app,

409
00:16:44,360 --> 00:16:46,009
especially if you're going to be pasting it

410
00:16:46,009 --> 00:16:48,199
into the Q&A discussions. That way, you're

411
00:16:48,199 --> 00:16:49,399
only posting in entries that are

412
00:16:49,399 --> 00:16:51,769
relevant to the current problem. Now the

413
00:16:51,769 --> 00:16:53,360
current version of Android Studio now

414
00:16:53,360 --> 00:16:55,699
clears the logcat when apps run, but that

415
00:16:55,699 --> 00:16:57,139
doesn't always work, so clearing it

416
00:16:57,139 --> 00:16:58,750
manually isn't a bad habit to get into.

417
00:16:58,750 --> 00:17:03,220
So we go ahead and re-run this again now.

418
00:17:03,220 --> 00:17:05,510
We should find we get the security

419
00:17:05,510 --> 00:17:08,270
exception, and you can see here,

420
00:17:08,270 --> 00:17:10,339
Permission denied missing internet

421
00:17:10,339 --> 00:17:12,709
permissions, in parentheses. So that

422
00:17:12,709 --> 00:17:14,270
doesn't look good but it is because we

423
00:17:14,270 --> 00:17:16,159
haven't given the app permission to

424
00:17:16,159 --> 00:17:18,349
access the internet yet. Now it's worth

425
00:17:18,349 --> 00:17:19,069
seeing what that

426
00:17:19,069 --> 00:17:21,589
looks like, and if I hadn't included this

427
00:17:21,589 --> 00:17:23,270
catch-all - and this is the code I'm

428
00:17:23,270 --> 00:17:27,980
talking about here, down for the catch

429
00:17:27,980 --> 00:17:30,770
exception on line 76 - if we hadn't have

430
00:17:30,770 --> 00:17:32,720
added that, we would have got a complete

431
00:17:32,720 --> 00:17:33,920
stack trace and the app would have

432
00:17:33,920 --> 00:17:35,960
crashed. So it's worth seeing what that

433
00:17:35,960 --> 00:17:37,970
looks like, so I'm going to comment out

434
00:17:37,970 --> 00:17:39,140
the code that catches all other

435
00:17:39,140 --> 00:17:40,400
exceptions. So let's go ahead and do that.

436
00:17:40,400 --> 00:17:42,440
So I'm just going to comment those two

437
00:17:42,440 --> 00:17:43,460
lines out there and leave the

438
00:17:43,460 --> 00:17:46,250
bottom closing code block, to make sure

439
00:17:46,250 --> 00:17:48,260
the code is still valid. And if you run

440
00:17:48,260 --> 00:17:55,160
that again now, this time the app has

441
00:17:55,160 --> 00:17:56,720
crashed, as you can see there, and then we

442
00:17:56,720 --> 00:17:58,610
look at the logcat - we've now got a

443
00:17:58,610 --> 00:18:02,810
stack trace with a fatal exception for

444
00:18:02,810 --> 00:18:05,810
AsyncTask 1. Now all this stuff in the

445
00:18:05,810 --> 00:18:08,030
logcat is a dump of what happened when

446
00:18:08,030 --> 00:18:10,220
the program crashed. The

447
00:18:10,220 --> 00:18:12,650
entries in red are a stack trace, and

448
00:18:12,650 --> 00:18:13,970
although it probably looks very

449
00:18:13,970 --> 00:18:16,640
confusing, it's also extremely useful to

450
00:18:16,640 --> 00:18:19,160
find out why your program crashed. So

451
00:18:19,160 --> 00:18:20,630
this first entry, as I mentioned at the

452
00:18:20,630 --> 00:18:23,630
top, is fatal exception AsyncTask hash

453
00:18:23,630 --> 00:18:25,850
1. Now the #1 is just a number

454
00:18:25,850 --> 00:18:28,130
generated by the Android code. If it

455
00:18:28,130 --> 00:18:30,260
set two background tasks away, then

456
00:18:30,260 --> 00:18:32,660
there'd be a hash 2 and so on. So

457
00:18:32,660 --> 00:18:34,010
don't worry about the actual number you

458
00:18:34,010 --> 00:18:35,960
see there - it'll just keep counting up if

459
00:18:35,960 --> 00:18:37,730
you restart the app without terminating

460
00:18:37,730 --> 00:18:39,950
it first. The bit we want to look at is a

461
00:18:39,950 --> 00:18:42,170
bit further down, and the quick way to

462
00:18:42,170 --> 00:18:44,510
spot what's immediately relevant is to

463
00:18:44,510 --> 00:18:46,850
look for the block of code that

464
00:18:46,850 --> 00:18:50,090
contains blue links. As I scroll down, and

465
00:18:50,090 --> 00:18:51,350
I might need to scroll across to see

466
00:18:51,350 --> 00:18:53,090
it, you can see these blue blue links

467
00:18:53,090 --> 00:18:54,670
over here, to the right-hand side. So

468
00:18:54,670 --> 00:18:57,350
these relate to line numbers in our own

469
00:18:57,350 --> 00:18:59,630
code. So much of the rest of these

470
00:18:59,630 --> 00:19:01,040
entries are coming from the Android

471
00:19:01,040 --> 00:19:04,160
framework, or the Java runtime, but the

472
00:19:04,160 --> 00:19:06,620
blue links relate to our code, so they're

473
00:19:06,620 --> 00:19:08,330
the bits we should really be focusing on.

474
00:19:08,330 --> 00:19:12,440
so that block that starts here - let me

475
00:19:12,440 --> 00:19:13,640
scroll up and have a bit of a

476
00:19:13,640 --> 00:19:15,860
look - Permission denied missing Internet

477
00:19:15,860 --> 00:19:17,990
permission. And we can see that if

478
00:19:17,990 --> 00:19:19,700
we scroll down here; Main

479
00:19:19,700 --> 00:19:22,940
Activity.kt line 51 in our main

480
00:19:22,940 --> 00:19:25,700
activity. So, that in turn, was called from

481
00:19:25,700 --> 00:19:27,680
line 38, as you can see here, and

482
00:19:27,680 --> 00:19:29,840
sometimes it's useful to track back

483
00:19:29,840 --> 00:19:31,940
through the code like that, to see how

484
00:19:31,940 --> 00:19:32,780
you got to the code

485
00:19:32,780 --> 00:19:34,850
that actually caused the error. In this

486
00:19:34,850 --> 00:19:36,260
case, though, it's a little bit simpler.

487
00:19:36,260 --> 00:19:38,480
There's no need to trace back because it

488
00:19:38,480 --> 00:19:40,130
wasn't the way that doInBackground was

489
00:19:40,130 --> 00:19:42,200
called that caused the error - it was the

490
00:19:42,200 --> 00:19:44,630
lack of internet permissions. So make a

491
00:19:44,630 --> 00:19:46,190
note of that exception - security

492
00:19:46,190 --> 00:19:48,080
exception - and in the next video, we'll

493
00:19:48,080 --> 00:19:50,210
actually catch that exception to prevent

494
00:19:50,210 --> 00:19:52,310
the program from crashing. And we'll also

495
00:19:52,310 --> 00:19:54,160
have a look at Android permissions. A

496
00:19:54,160 --> 00:19:56,630
major change was introduced in Android

497
00:19:56,630 --> 00:19:58,880
6 Marshmallow, and continues to apply

498
00:19:58,880 --> 00:20:00,860
in Android 7 and 8, and we'll see

499
00:20:00,860 --> 00:20:03,050
how to fix the cause of that error. So,

500
00:20:03,050 --> 00:20:06,190
see you in the next video.

