1 00:00:05,520 --> 00:00:08,910 OK so we're gonna start with the basics with this application, 2 00:00:08,910 --> 00:00:14,220 and the first thing we need to do before parsing the json data is to download it. 3 00:00:14,220 --> 00:00:20,370 So I'm going to leave the user interface until later. To start with we'll download the data using an asynchronous 4 00:00:20,370 --> 00:00:24,930 task, which is similar to what we did in the top 10 downloader app. 5 00:00:24,930 --> 00:00:32,390 So let's start now, and we're going to come over here to our package name, we'll right click over here, 6 00:00:32,390 --> 00:00:42,210 select new, Kotlin Class, and we're going to call this one GetRawData. To save a bit of time I'm going to choose 7 00:00:42,210 --> 00:00:50,390 Class there in the drop down. We'll close down the log cat for now. So to start with we're going to extend the async 8 00:00:50,390 --> 00:00:56,270 class, so that GetRawData can perform it's downloading on a separate background thread. 9 00:00:56,270 --> 00:00:59,900 And again this is exactly the same as we did in the top 10 downloader app, 10 00:00:59,900 --> 00:01:01,550 and once again we're providing a string, 11 00:01:01,550 --> 00:01:05,540 or we're going to provide a string which will be the URL to download from, 12 00:01:05,540 --> 00:01:08,020 and we'll get back a string containing our data. 13 00:01:08,020 --> 00:01:16,080 So let's go ahead and do that. So I'm going to put a space colon space, and it's going to be an async task, and we want a 14 00:01:16,080 --> 00:01:19,250 diamond operator so left and right, less than and greater than 15 00:01:19,250 --> 00:01:26,420 signs there, then we're going to do a string, void, string, again you've seen that in the top 10 downloaders app, then 16 00:01:26,420 --> 00:01:31,610 add parentheses on the end there. Now we've got an error, but before implementing the required methods, 17 00:01:31,610 --> 00:01:36,590 I'm going to create an enum to hold a list of download statuses. 18 00:01:36,590 --> 00:01:42,640 Now we saw this also in the previous app, when the Google YouTube player, to find an enum to hold the result 19 00:01:42,640 --> 00:01:47,030 codes that we could get back if anything went wrong when playing the videos. 20 00:01:47,030 --> 00:01:53,000 So here we want a way to tell the calling processes whether the download succeeded or what the state 21 00:01:53,000 --> 00:01:56,270 of the download is. So I'm going to use an enum for that. 22 00:01:56,270 --> 00:02:01,130 Now I have covered enums in the Kotlin tutorial section too, so refer to that section if you're 23 00:02:01,130 --> 00:02:05,840 not sure what enums are. So I'll put this definition above the class here, 24 00:02:05,840 --> 00:02:15,510 the class definition, so that's enum, class, then DownloadStatus, 25 00:02:15,510 --> 00:02:20,540 then we put our left and right curly brace there. Then within there we put 26 00:02:20,540 --> 00:02:26,240 OK comma space, IDLE comma space NOT_INITIALIZED, 27 00:02:26,240 --> 00:02:37,740 comma space FAILED_OR_EMPTY comma space PERMISSIONS_ERROR comma space, 28 00:02:37,740 --> 00:02:42,590 and the last one, ERROR. So the download status enums got 29 00:02:42,590 --> 00:02:47,150 all the states that this class is going to be in, in other words all the possibilities. 30 00:02:47,150 --> 00:02:50,040 So OK means that we've got some valid data. 31 00:02:50,040 --> 00:02:55,310 IDLE means that it's not processing anything, NOT-INITIALIZED means that we haven't got a valid URL 32 00:02:55,310 --> 00:02:56,330 to download. 33 00:02:56,330 --> 00:03:01,010 It's an error condition, because we won't be able to set it until a download's been attempted. Now 34 00:03:01,010 --> 00:03:06,920 FAILED_OR_EMPTY means that we either failed to download anything or the data came back empty. 35 00:03:06,920 --> 00:03:11,330 And the last two errors there, PERMISSIONS_ERROR and ERROR, indicate errors either with the permissions 36 00:03:11,330 --> 00:03:14,430 or with some other error that we haven't identified. 37 00:03:14,430 --> 00:03:19,340 Now you can obviously go into more detail and create more statuses if you really wanted to, but that 38 00:03:19,340 --> 00:03:21,290 will work for our purposes here. 39 00:03:21,290 --> 00:03:25,190 So the next thing I want to do is add a log tag for our debuggings. So let's do that, this time within the 40 00:03:25,190 --> 00:03:34,700 class, private val TAG equals double quotes GetRawData. 41 00:03:34,700 --> 00:03:45,680 Then on the next line we're going to do a private var downloadStatus equals DownloadStatus.IDLE, and you 42 00:03:45,680 --> 00:03:51,800 can see that I've also declared a variable to hold the download status, and we've initialized that to IDLE 43 00:03:51,800 --> 00:03:57,380 because our class instance won't be doing anything when it's first created. Now we've got an error because 44 00:03:57,380 --> 00:04:01,550 we haven't implemented the required methods for an async task. 45 00:04:01,550 --> 00:04:07,190 So let's actually sort that out. Now we need to override the required async task functions, 46 00:04:07,190 --> 00:04:13,250 so we can do a command n, making sure you're within the class definition, or alt insert on a PC, and then 47 00:04:13,250 --> 00:04:18,890 select override methods. Alternatively command 48 00:04:18,890 --> 00:04:22,630 O on a Mac or control O, would get straight to here as well. 49 00:04:22,630 --> 00:04:27,290 So the ones we want here are doInBackground and we also want onPostExecute, 50 00:04:27,290 --> 00:04:32,190 so I'm going to select both of those, then click OK. 51 00:04:32,190 --> 00:04:36,500 The error's now disappeared as you can see. Now the doInBackground 52 00:04:36,500 --> 00:04:42,410 function's going to be pretty similar to the code in the top 10 downloader. There are minor differences, because 53 00:04:42,410 --> 00:04:47,810 we're going to set the download status, and I also want to introduce a catch block to trap any errors, but we'll 54 00:04:47,810 --> 00:04:49,070 come to that in a minute. 55 00:04:49,070 --> 00:04:59,780 So let's start some coding there, we'll delete TODO, and we're going to put if parentheses params, zero 56 00:04:59,780 --> 00:05:01,400 in square brackets, 57 00:05:01,400 --> 00:05:10,170 is equal to null, open a code block and there's going to be download status is equal to download status dot NOT 58 00:05:10,170 --> 00:05:17,420 INITIALIZED, return, then in double quotes No URL specified. 59 00:05:17,420 --> 00:05:21,940 So this first bit of code that I've added just checks that the URL we get isn't null. 60 00:05:21,940 --> 00:05:25,330 Now the function receives an array of strings or a string 61 00:05:25,330 --> 00:05:28,170 array, if you're more used to thinking of it that way. 62 00:05:28,170 --> 00:05:35,470 What's interesting here is the nullable type string question mark, up here. 63 00:05:35,470 --> 00:05:41,530 So this means that the individual elements of params can be null. Params itself however can't be null, 64 00:05:41,530 --> 00:05:46,090 and we can actually get Android Studio to verify that by changing our 65 00:05:46,090 --> 00:05:48,490 null check. So I could change that there to 66 00:05:48,490 --> 00:05:55,540 putting, if params is equal to null, and when I do that, if I hover over that, you can see 'Condition params is equal 67 00:05:55,540 --> 00:06:01,450 to null is always false'. So we can be sure we definitely get a non null array, 68 00:06:01,450 --> 00:06:04,660 but the individual elements it contains might be null. 69 00:06:04,660 --> 00:06:05,530 So that's what the type, 70 00:06:05,530 --> 00:06:10,410 that's why rather, the type is string question mark, and why we start off with a null check. 71 00:06:10,410 --> 00:06:15,090 So pay really careful attention to the code that Android Studio generates, and 72 00:06:15,090 --> 00:06:17,090 be aware that it can change. 73 00:06:17,090 --> 00:06:22,300 Google change things frequently, and if you generate the same function a week later, you might well get 74 00:06:22,300 --> 00:06:24,100 slightly different code. 75 00:06:24,100 --> 00:06:29,110 In fact if you review the top 10 downloader app, the parameter name was different when it generated the 76 00:06:29,110 --> 00:06:29,800 same function 77 00:06:29,800 --> 00:06:35,350 back then. Alright so I'm going to put that line back, I'm going to undo that, and that warning goes away, 78 00:06:35,350 --> 00:06:38,800 and not only that, it's now doing something useful. 79 00:06:38,800 --> 00:06:43,840 Alright so we checked that we've been given a URL and the function was called. We don't know if it's 80 00:06:43,840 --> 00:06:47,830 a valid URL yet, but we can at least check that we've got something. 81 00:06:47,830 --> 00:06:53,490 If not, if the first element of params is null, then we set the standard to NOT_INITIALIZED, 82 00:06:53,490 --> 00:06:56,650 return the text "No url specified". 83 00:06:56,650 --> 00:07:02,470 So let's now enclose the rest of the code and this function inside a try block, so that we can catch any exceptions 84 00:07:02,470 --> 00:07:04,990 that are raised while downloading. 85 00:07:04,990 --> 00:07:17,680 So I'll do that down here, try, then within that I'm going to put downloadStatus equals DownloadStatus.OK, return 86 00:07:17,680 --> 00:07:31,370 URL in uppercase, parentheses, params 0 in square brackets, closing parentheses dot readText. We 87 00:07:31,370 --> 00:07:38,960 need to accept that import, and again that code's very similar to the top 10 downloader function, 88 00:07:38,960 --> 00:07:44,510 once we reduced it to a single line. Now the import for URL doesn't always get added automatically 89 00:07:44,510 --> 00:07:46,250 and you saw that it didn't for me. 90 00:07:46,250 --> 00:07:52,730 If it doesn't, you can just hold down alt enter, and choose Java dot net dot url, and you see again that I did that. 91 00:07:52,730 --> 00:07:56,600 Now there should only be one value passed in the params array. 92 00:07:56,600 --> 00:08:03,290 So we pick up the first one in params zero, this code here, to make sure that we're using elements zero. 93 00:08:03,290 --> 00:08:10,450 As I said, this may not be a valid URL but we're going to rely on the catch block to detect an invalid URL. 94 00:08:10,450 --> 00:08:16,940 Now we set the status to OK using the constant defined in our enum, which is a common approach. 95 00:08:16,940 --> 00:08:20,610 So in other words we assume everything's going to work fine, but then change the status, 96 00:08:20,610 --> 00:08:21,590 even exceptions, 97 00:08:21,590 --> 00:08:29,150 raised. Now the catch block I'm about to add's the same as we originally had in the top 10 downloader. 98 00:08:29,150 --> 00:08:38,659 So let's go ahead and do that and actually add it, so we're going to do a catch, parentheses e colon exception, then a 99 00:08:38,659 --> 00:08:45,200 code block, and then we're going to put val 100 00:08:45,200 --> 00:08:49,880 errorMessage equals when, then in parentheses e. 101 00:08:49,880 --> 00:08:55,060 Then open a code block, then within that we're going to put is Malformed 102 00:08:55,060 --> 00:09:04,000 URLException, end of that we'll have arrow token and then a code block, then we're going to put downloadStatus is equal 103 00:09:04,000 --> 00:09:17,760 to DownloadStatus.NOT_INITIALIZED, then in double quotes on the next line, doInBackground colon Invalid 104 00:09:17,760 --> 00:09:26,780 URL space dollar sign, left and right curly braces, e.message. And what we might do to save a bit of time 105 00:09:26,780 --> 00:09:30,380 here is we might copy and paste some of these. 106 00:09:30,380 --> 00:09:34,020 So I'm going to put is Malformed exception there. I'm going to copy that, 107 00:09:34,020 --> 00:09:36,990 because we've got a couple more we want to put, we want to try. 108 00:09:36,990 --> 00:09:46,280 Next one is going to be IO exception so let's do that one, so is IOException, and 109 00:09:46,280 --> 00:10:00,780 for that one we're going to put FAILED_OR_EMPTY, the status will be failed or empty, and we'll put for the text "IO Exception 110 00:10:00,780 --> 00:10:09,630 reading data" colon and then we'll put the e.message again, there again. The next one we want is security exceptions, 111 00:10:09,630 --> 00:10:11,790 so let's paste that as well. 112 00:10:11,790 --> 00:10:24,120 So is SecurityException, and for that one we're going to put permissions error, dot PERMISSIONS_ERROR, and for 113 00:10:24,120 --> 00:10:37,490 the actual text let's go with "Security exception Needs permission?", and 114 00:10:37,490 --> 00:10:44,150 and we'll leave that e.message in there for the specific error. Then we also need to do down here, after the last is, we need 115 00:10:44,150 --> 00:10:51,980 to add an else, so else code block, sorry arrow token and then block block, and the else is going to be downloadStatus is 116 00:10:51,980 --> 00:10:54,760 equal to DownloadStatus.ERROR. 117 00:10:54,760 --> 00:10:59,780 So that's that generic error that we haven't been able to identify actually what happened, and the 118 00:10:59,780 --> 00:11:10,490 text we're returning is "Unknown error" colon and then space dollar, left and right curly braces, e.message. 119 00:11:10,490 --> 00:11:15,400 Then moving down, down here now, outside of the val error message, 120 00:11:15,400 --> 00:11:25,520 we have a Log.e this time, because it is actually an error, Log.e TAG, error message, then we're going 121 00:11:25,520 --> 00:11:30,160 to return errorMessage. 122 00:11:30,160 --> 00:11:34,420 Alright so that's our function now and our try catch block. 123 00:11:34,420 --> 00:11:40,140 So basically what we're doing is we're checking for a malformed URL, and then any IO exceptions that 124 00:11:40,140 --> 00:11:43,450 actually are thrown, that's these two here. 125 00:11:43,450 --> 00:11:49,750 And there's also a check for security, or at a security exception, if we forget to request permission to access 126 00:11:49,750 --> 00:11:54,160 the Internet. Now if there was an exception, we'll get to the code after the catch blocks 127 00:11:54,160 --> 00:11:59,500 when we return the error message. So that's our doInBackground function completed. 128 00:11:59,500 --> 00:12:04,030 We made a few changes and some minor improvements, but it's really basically the same code as we 129 00:12:04,030 --> 00:12:06,400 used in the top 10 downloader. 130 00:12:06,400 --> 00:12:11,680 So I'll stop the video here, and in the next one we'll create the code for on post execute. 131 00:12:11,680 --> 00:12:12,660 So see you in the next video.