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.