1 00:00:05,670 --> 00:00:11,030 In this video, we're going to write the class that'll be responsible for parsing the json data that we've 2 00:00:11,030 --> 00:00:14,750 downloaded. So I'm going to go ahead and create a new class, 3 00:00:14,750 --> 00:00:17,540 right clicking the package, 4 00:00:17,540 --> 00:00:24,530 New, Kotlin File/Class, I'm going to select Class to save a bit of typing, and this one is going to be called 5 00:00:24,530 --> 00:00:31,640 GetFlickerJsonData. 6 00:00:31,640 --> 00:00:36,840 Alright so this class will be an async task, so we're going to start off very similar to get raw data, 7 00:00:36,840 --> 00:00:50,090 so add parentheses after the class name, and we're going to do private val listener colon OnDataAvailable, 8 00:00:50,090 --> 00:00:57,190 then right parentheses colon, then async task, 9 00:00:57,190 --> 00:01:03,300 and then we want a diamond operator, less than and greater than sign, signs string comma Void 10 00:01:03,300 --> 00:01:06,630 comma. This time I'm going to do something different, instead of putting string for the third argument, 11 00:01:06,630 --> 00:01:11,190 it's going to be array list, diamond operator again, that's the less than 12 00:01:11,190 --> 00:01:16,010 and greater than sign, operators, in it photo. 13 00:01:16,010 --> 00:01:19,500 Then we need to add parentheses after that as well, before the left 14 00:01:19,500 --> 00:01:27,420 curly brace. Now this is an async task that takes a string and returns a list of photo objects. 15 00:01:27,420 --> 00:01:29,940 Now once again we're not using the progress parameter, 16 00:01:29,940 --> 00:01:32,880 so that's why we're leaving this second argument as void. 17 00:01:32,880 --> 00:01:34,530 Now there's a couple of errors here. 18 00:01:34,530 --> 00:01:39,570 Firstly we haven't implemented the doInBackground method, so we need to do that to avoid that error, 19 00:01:39,570 --> 00:01:43,260 but also we haven't defined the callback interface yet. 20 00:01:43,260 --> 00:01:47,560 I'm going to add a tag for logging as well, so let's do that before we add the interface 21 00:01:47,560 --> 00:01:54,910 as well, private val tag is equal to double quotes GetFlickrJsonData. 22 00:01:54,910 --> 00:02:01,810 Now let's create the interface, so interface, 23 00:02:01,810 --> 00:02:11,790 OnDataAvailable, left and right curly braces. Then we put fun onDataAvailable, 24 00:02:11,790 --> 00:02:21,700 parentheses data colon list, then the diamond operators, less than and greater than, photo, then closing right parentheses, 25 00:02:21,700 --> 00:02:31,940 and on the next line, fun onError, parentheses exception colon Exception with a capital E. 26 00:02:31,940 --> 00:02:39,140 Alright so what have I done here. Well we want to let whatever uses this class, know if there's been an error. 27 00:02:39,140 --> 00:02:45,090 Now we could use an enum, just like we did in get raw data, and include that in the onDataAvailable function. 28 00:02:45,090 --> 00:02:46,620 That would work fine, and 29 00:02:46,620 --> 00:02:51,450 we've already seen how to do something like that already, but I've taken a different approach here, and 30 00:02:51,450 --> 00:02:58,050 I've done that because it's not as obvious what could go wrong when passing json. Now http errors are 31 00:02:58,050 --> 00:02:59,460 clearly documented, and 32 00:02:59,460 --> 00:03:05,040 we could've returned the http response code instead of a status in get raw data, 33 00:03:05,040 --> 00:03:08,540 but here we don't have such a ready list of failure codes. 34 00:03:08,540 --> 00:03:12,600 Now the json parser throws exceptions when things go wrong. 35 00:03:12,600 --> 00:03:18,730 Our get Flickr json data class will pass the exception onto the caller, via this onError function that 36 00:03:18,730 --> 00:03:21,060 we've defined in the interface. 37 00:03:21,060 --> 00:03:26,790 This also provides an opportunity to show one way of dealing with exceptions when they happen on another 38 00:03:26,790 --> 00:03:33,150 thread. Now a normal try catch block isn't much use, because the calling code would have moved on by the 39 00:03:33,150 --> 00:03:35,820 time our async task executes. 40 00:03:35,820 --> 00:03:40,870 So what I mean by that is, you can't do something like this in main activity, when we call the get 41 00:03:40,870 --> 00:03:42,590 raw data dot execute method. 42 00:03:42,590 --> 00:03:46,610 So I'm just going to type some code and show you what I mean. So basically 43 00:03:46,610 --> 00:04:04,040 what I'm saying is, after this line here, we cannot do try then catch, E colon exception, and then put our execute in there. 44 00:04:04,040 --> 00:04:10,180 I'm just going to comment, delete that commented out code as well now. So as we've already seen, our onCreate 45 00:04:10,180 --> 00:04:14,240 function ends before the coding get raw data is executed. 46 00:04:14,240 --> 00:04:19,089 So if get raw data throws an exception, we'll no longer be inside this try catch block, 47 00:04:19,089 --> 00:04:24,910 so the exception won't be caught. And you can't catch an exception that's thrown by code, executing in a 48 00:04:24,910 --> 00:04:28,390 different thread, which is what I've just attempted to do here. 49 00:04:28,390 --> 00:04:32,590 So I'm going to put that code back to how it was, and obviously to make that code valid we would've put something 50 00:04:32,590 --> 00:04:38,690 like that, and put some code in here to do some error processing. 51 00:04:38,690 --> 00:04:40,810 So the point wasn't the fact that we had an error there. 52 00:04:40,810 --> 00:04:46,840 The point was again, you can't catch an exception that's thrown by code executing in a different thread, 53 00:04:46,840 --> 00:04:49,620 and again that's what we're trying to do here if we left the code like this. 54 00:04:49,620 --> 00:04:58,940 So I'm just going to undo those code changes, so we have it back to how it was prior to that. 55 00:04:58,940 --> 00:05:04,850 What I will do is delete some of this commented code from previous videos. 56 00:05:04,850 --> 00:05:09,390 Alright so let's go back to get Flickr json data again. 57 00:05:09,390 --> 00:05:14,720 OK, so what I've done is add another function to the interface, the onError function. 58 00:05:14,720 --> 00:05:21,190 And if our code had an error, or has an error, while parsing the json data, it's going to call the onError function 59 00:05:21,190 --> 00:05:27,620 and pass the exception as an argument. The code that uses get Flickr json data can use that exception 60 00:05:27,620 --> 00:05:32,660 to report the error to the user, or do whatever else it needs to do with that error. And we'll simulate an 61 00:05:32,660 --> 00:05:36,290 error when we've got the code written so we can say this in action. 62 00:05:36,290 --> 00:05:42,540 So moving on we need to implement the doInBackground function that an async task must have. Now doIn 63 00:05:42,540 --> 00:05:45,260 Background is going to perform the parsing of the data. 64 00:05:45,260 --> 00:05:51,600 We're going to give it a string containing the json, and it'll parse the data out into photo objects. 65 00:05:51,600 --> 00:05:59,670 So I'm going to get Android Studio to create the stub for me using control o, we'll do that, that works on both operating systems. 66 00:05:59,670 --> 00:06:04,370 Now the shortcut to implement functions or methods is usually control i, 67 00:06:04,370 --> 00:06:06,860 but that only shows required interfaces. 68 00:06:06,860 --> 00:06:13,800 So when I use control i, we do get the get doInBackground function but not onPostExecute. 69 00:06:13,800 --> 00:06:17,070 So I'm going to cancel that and use control o instead, and 70 00:06:17,070 --> 00:06:21,800 you can see now that we've got both our doInBackground and onPostExecute. So I'm choosing both of 71 00:06:21,800 --> 00:06:26,160 those and clicking on OK, and you can see now the class definition error has now gone 72 00:06:26,160 --> 00:06:31,610 away because we've managed to fix that, by implementing those required functions, 73 00:06:31,610 --> 00:06:34,320 or at least we've created the stubs for them anyway. 74 00:06:34,320 --> 00:06:40,520 So let's go ahead and put a bit of code in there, at least a logging bit of code for the doInBackground. So we'll 75 00:06:40,520 --> 00:06:52,740 do a Log.d parentheses TAG comma doInBackground starts. 76 00:06:52,740 --> 00:06:59,060 What I might do is I'll just undo that. I'll leave the TODO in there for now, 77 00:06:59,060 --> 00:07:04,880 but I will put the logging back in again, because we obviously haven't implemented any code in 78 00:07:04,880 --> 00:07:06,290 the doInBackground. 79 00:07:06,290 --> 00:07:14,870 And for the onPostExecute, we'll leave the super call in there. We'll also paste in the TAG again, but this time we'll 80 00:07:14,870 --> 00:07:16,670 obviously change the name of that to onPost 81 00:07:16,670 --> 00:07:24,890 Execute starts. So onPostExecute starts, we'll leave the call to super there as well. 82 00:07:24,890 --> 00:07:29,450 So I've logged the entry into the functions as usual, and I've mentioned a few times 83 00:07:29,450 --> 00:07:36,350 now, that's a great way to understand what's going on while you're learning. Alright so let's write the doInBackground 84 00:07:36,350 --> 00:07:37,730 function first. 85 00:07:37,730 --> 00:07:43,070 Now we're going to use to the java org dot json package to parse our data, 86 00:07:43,070 --> 00:07:46,830 and that's going to throw a json exception if there's an error in the data. 87 00:07:46,830 --> 00:07:51,110 So I'm going to wrap all the parsing in a try block, and I'm going to delete the two TODO line now because 88 00:07:51,110 --> 00:07:57,770 we we're about to do that. But a good idea though with this TODO, to leave that in your code for stubs that 89 00:07:57,770 --> 00:08:03,020 you haven't implemented yet, just as a reminder that you need to go back and change it. As soon as you start doing or implementing 90 00:08:03,020 --> 00:08:07,720 the code, delete the TODO as I've done there. Alright so we're going to start, 91 00:08:07,720 --> 00:08:18,710 try, we'll add a code block, and within the code block we'll put val json data is equal to json object, note 92 00:08:18,710 --> 00:08:27,360 the capitalisations there, parentheses params, square brackets zero in the middle, then we're closing our parentheses. 93 00:08:27,360 --> 00:08:32,100 Now we're getting an error here because we haven't yet caught any exception that may be thrown, but 94 00:08:32,100 --> 00:08:34,080 that'll go when we add the catch block. 95 00:08:34,080 --> 00:08:40,100 Now to parse json data, using the classes in the org.json package, we create a new json object 96 00:08:40,100 --> 00:08:44,240 and parse the data to its constructor, and we're doing that on line 23. 97 00:08:44,240 --> 00:08:50,590 Now before I move on, notice the parameter that's declared for doInBackground. Android Studio updated 98 00:08:50,590 --> 00:08:57,620 since I recorded the top 10 downloader app. We've now got a slightly better name for the parameter, params here. 99 00:08:57,620 --> 00:09:00,650 It's a bit better than p zero which it was previously. 100 00:09:00,650 --> 00:09:06,170 Now the information we want is contained in a json array called items. 101 00:09:06,170 --> 00:09:10,700 So I'm going to add the code to read the array from the json data, then we'll have a quick look at our source 102 00:09:10,700 --> 00:09:23,570 data again. So on the next line we're going to type val items array is equal to json data dot get 103 00:09:23,570 --> 00:09:29,780 json array, parentheses, then in double quotes items. 104 00:09:29,780 --> 00:09:35,980 Now when we were looking at the flickr json data earlier, we saw that all the values have names. So I'm going to 105 00:09:35,980 --> 00:09:42,690 switch back to Firefox, and you can see up here, is items. 106 00:09:42,690 --> 00:09:46,640 So that's the array containing all the items we're interested in, starting with this, 107 00:09:46,640 --> 00:09:51,370 we can't really see the square bracket, because we're now not looking at the raw json data, 108 00:09:51,370 --> 00:09:57,680 we're looking at formatted data. What we can do though is just open another browser, I'm going to do that now. 109 00:09:57,680 --> 00:10:06,050 We'll open Chrome, then I'll paste that same link in, and we'll see the raw representation. 110 00:10:06,050 --> 00:10:10,630 So you can see over here we've got items, we've got that left square bracket that I was talking about. 111 00:10:10,630 --> 00:10:13,840 So that's basically an array containing all the items we're interested in, and 112 00:10:13,840 --> 00:10:19,470 again it starts with that first opening bracket, and you can see the groups of items separated by a comma, 113 00:10:19,470 --> 00:10:23,670 and the opening and closing, the left and right curly braces. 114 00:10:23,670 --> 00:10:30,300 So within that array, in each of the items consists of these values between those braces, title, link, media etc. 115 00:10:30,300 --> 00:10:34,920 So the first thing we need to do is get the array object, which is all the individual items, and then 116 00:10:34,920 --> 00:10:39,750 we can go through the array and extract out the individual items, and basically access the values we 117 00:10:39,750 --> 00:10:47,230 want. Go back to the code. So we've got this code here on line 24, 118 00:10:47,230 --> 00:10:53,020 then it gets a json array object from the data by calling the get json array function, and specifying 119 00:10:53,020 --> 00:11:00,790 the name of the array, which is items. Now obviously that's a match for this name of the item, name of the array, in the json data, and 120 00:11:00,790 --> 00:11:06,930 we can see that also in Firefox, it's called items as well. 121 00:11:06,930 --> 00:11:12,180 What we can do is loop through all the items in a json array, just as we can with a normal array. 122 00:11:12,180 --> 00:11:16,140 Although there are some differences in the behavior, because we can't assume that all the objects in 123 00:11:16,140 --> 00:11:21,750 a json array are of the same type. In other words, there could be other arrays inside this array. 124 00:11:21,750 --> 00:11:26,430 Now if you want more information or this org.json package, Google have actually produced some decent 125 00:11:26,430 --> 00:11:32,460 documentation, specifically on the Android implementation. I'm just going to go quickly to a browser and we'll 126 00:11:32,460 --> 00:11:35,790 paste that in. So check that out. 127 00:11:35,790 --> 00:11:40,990 You'll find out a lot more about these classes and what they actually do. 128 00:11:40,990 --> 00:11:43,510 Alright so back to Android Studio. 129 00:11:43,510 --> 00:11:50,530 So at this point what we need to do is loop through the array, pulling out the information we're interested in. 130 00:11:50,530 --> 00:11:52,410 So let's go ahead and do that. 131 00:11:52,410 --> 00:12:05,080 So on the next line I'm going to do for, parentheses i in zero until itemsArray dot length, closing parentheses, 132 00:12:05,080 --> 00:12:15,920 and open a code block, and within the code block I'm going to type val json photo is equal to itemsArray dot 133 00:12:15,920 --> 00:12:18,450 getJSONObject, 134 00:12:18,450 --> 00:12:26,310 noting it's getJSONObject and not get json array this time. Then parentheses i, so we're getting that individual 135 00:12:26,310 --> 00:12:29,980 photo object from within the array. 136 00:12:29,980 --> 00:12:34,720 Then what we want to do is go through and get each individual property within that particular entry. So we're going to start with 137 00:12:34,720 --> 00:12:46,720 val title is equal to json photo dot getString parentheses double quotes title. 138 00:12:46,720 --> 00:12:50,760 Let's add a few more, we need another five, we're going to do author, author ID, tags, 139 00:12:50,760 --> 00:12:56,610 json media and also link, so we'll do another five there. 140 00:12:56,610 --> 00:12:58,740 So the next one's going to be title, 141 00:12:58,740 --> 00:13:11,940 sorry the first one was title, the next one's going to be author, and we're going to do author id, tags, json media. 142 00:13:11,940 --> 00:13:17,990 That's going to be a different line of code which we'll talk about shortly, then photoUrl. 143 00:13:17,990 --> 00:13:23,910 Then let's go ahead and change it on the right hand side, so we've got title as the first line, author, the field name 144 00:13:23,910 --> 00:13:27,890 is author, next one, author id is author underscore id, 145 00:13:27,890 --> 00:13:33,740 and you go back and check the names to make sure that we're typing them correctly. 146 00:13:33,740 --> 00:13:37,290 You want to make sure that they're identical. We can see in this particular case, 147 00:13:37,290 --> 00:13:39,570 author underscore id is the actual name, 148 00:13:39,570 --> 00:13:47,900 so making sure that they both match in the code. Alright so moving on, tags is the next one. 149 00:13:47,900 --> 00:13:51,380 json media I'm going to leave because we're going to do something separate with that, 150 00:13:51,380 --> 00:13:56,580 and the last one, val photoUrl, we're going to do get string, m. 151 00:13:56,580 --> 00:14:00,040 And there's actually one more we need to do and I'm going to paste that in as well, 152 00:14:00,040 --> 00:14:05,360 and that one's going to be link, but we're going to do something slightly different with that. 153 00:14:05,360 --> 00:14:11,300 So we've got json media, so up until here, everything's pretty straightforward, the title, the author, the author 154 00:14:11,300 --> 00:14:12,620 ID and the tags, 155 00:14:12,620 --> 00:14:17,540 but json media, here we're going to do something a little bit different. So instead of putting dot getString, 156 00:14:17,540 --> 00:14:25,190 we're going to put dot getJSONObject parenthesis media. 157 00:14:25,190 --> 00:14:31,520 And from within that, on the next line the photoUrl is extracting out the property m for that particular 158 00:14:31,520 --> 00:14:33,660 object media. Then the link, 159 00:14:33,660 --> 00:14:35,360 we're also going to do something similar to that, 160 00:14:35,360 --> 00:14:52,420 so photoUrl dot replaceFirst m.jpg comma underscore b.jpg. 161 00:14:52,420 --> 00:14:57,610 Alright so I'm going to explain this now, what we've just done. So inside this loop, this code here, 162 00:14:57,610 --> 00:15:02,050 what we're doing is we're retrieving the json objects one by one and pulling out the string values 163 00:15:02,050 --> 00:15:03,280 that we need. 164 00:15:03,280 --> 00:15:07,720 But the one that needed special attention that I alluded was line 33, 165 00:15:07,720 --> 00:15:11,770 the media value. The string that we want is embedded inside it, 166 00:15:11,770 --> 00:15:15,670 but in another object called m. So if we go back and have a look 167 00:15:15,670 --> 00:15:19,390 you can see therefore our media, this media there. 168 00:15:19,390 --> 00:15:22,640 We've got another object m, which is embedded inside that, 169 00:15:22,640 --> 00:15:27,970 and that's the reason that we're first retrieving media, then we're retrieving the string, but from the json 170 00:15:27,970 --> 00:15:31,870 object photo that was returned from the call to 171 00:15:31,870 --> 00:15:36,220 jsonPhoto.getJSONObject, and that's how we're getting the url. Now the link here is also 172 00:15:36,220 --> 00:15:38,530 interesting. To explain what's going on there 173 00:15:38,530 --> 00:15:42,490 I'm going to start by explaining what we're going to use those fields for. 174 00:15:42,490 --> 00:15:49,180 Now the photo url value will become the image field of the photo object, so it's passed as the last parameter 175 00:15:49,180 --> 00:15:50,720 to the constructor. 176 00:15:50,720 --> 00:15:55,660 Now if we have a look at the photo class, the last parameter the constructor sets the value of 177 00:15:55,660 --> 00:15:58,090 image, right up here. 178 00:15:58,090 --> 00:16:02,500 So we're going to be using that field to display the image for each photo in the list. 179 00:16:02,500 --> 00:16:08,980 Now when an item in the list is tapped, we'll launch another activity to display the photograph much larger, 180 00:16:08,980 --> 00:16:10,660 so that it fills the screen. 181 00:16:10,660 --> 00:16:17,240 So to do that we're going to use this link value, link value, so going back to GetFlickerJsonData. 182 00:16:17,240 --> 00:16:23,200 So image will give us the url or the photo to show in the initial list, and link will provide the url 183 00:16:23,200 --> 00:16:28,060 of the full size picture. Now whenever we're going to be using urls in an app, 184 00:16:28,060 --> 00:16:34,090 it's a good idea to check them out in a browser first, to make sure they work and provide what you expected. 185 00:16:34,090 --> 00:16:39,420 So let's do that. So going back to the data again, 186 00:16:39,420 --> 00:16:46,970 and for one of these images, I'm going to choose this one here, 187 00:16:46,970 --> 00:16:53,670 I'm going to paste that in another tab. And you can see that loads the picture fine, 188 00:16:53,670 --> 00:16:55,290 so we can be happy with that one, 189 00:16:55,290 --> 00:16:59,550 and you could test a few more at random and if this was a mission critical app, then you probably should, 190 00:16:59,550 --> 00:17:01,710 but I'm happy with this for now. 191 00:17:01,710 --> 00:17:07,359 But next is the link value, so again I'm going to copy that and paste it into a new tab. 192 00:17:07,359 --> 00:17:18,369 Lets copy that again, new tab, paste it in. 193 00:17:18,369 --> 00:17:22,970 Now this looks good from the point of view of displaying the photograph, but it hasn't actually loaded 194 00:17:22,970 --> 00:17:24,920 the photo, again it, 195 00:17:24,920 --> 00:17:30,560 instead it's gone into sort of a slide show page, where you can move backwards and forwards. You can see the 196 00:17:30,560 --> 00:17:34,520 little slide show indicators there, through a set of photos. 197 00:17:34,520 --> 00:17:40,430 So that's great for viewing in a browser, but not much use to us for displaying the image full screen. 198 00:17:40,430 --> 00:17:46,070 So let's have another look at the flickr page. I'm going to copy everything in the url and up to, but not including, the format parameter. 199 00:17:46,070 --> 00:17:55,690 You can go back and open a new tab, and 200 00:17:55,690 --> 00:17:58,120 actually let's go back to Firefox where we can see things are a little bit clearer. 201 00:17:58,120 --> 00:18:05,420 So let's do that, new tab, well actually we'll just copy that exact 202 00:18:05,420 --> 00:18:14,340 url again, and back to Firefox, to Firefox, and we're going to paste that link in again. 203 00:18:14,340 --> 00:18:18,770 It's a smaller link without all the format that equals json etc. 204 00:18:18,770 --> 00:18:22,690 So when I do that in Firefox you can see we're seeing the images, 205 00:18:22,690 --> 00:18:29,230 but obviously back here, in chrome, we're not seeing the images when we do that. We're getting the XML instead. 206 00:18:29,230 --> 00:18:38,330 Now at the bottom of each entry is a little box with the title media files, containing a link to a jpeg. 207 00:18:38,330 --> 00:18:43,210 You'll probably see it more clearly with Firefox, down here media files. 208 00:18:43,210 --> 00:18:48,720 Now the link's slightly different to the one we looked at a minute ago. Instead of underscore m.jpg 209 00:18:48,720 --> 00:18:55,100 it's got underscore b.jpg, see under there, so basically it's a bigger version of the picture, 210 00:18:55,100 --> 00:18:59,920 and this time it's just a simple jpeg rather than a slideshow, which is exactly what we want here. 211 00:18:59,920 --> 00:19:02,760 And we can click on that to see what happens. 212 00:19:02,760 --> 00:19:04,710 We see we just get the image and there's no slideshow there now. 213 00:19:04,710 --> 00:19:11,250 Now because it's documented, it should be safe for us to use this. 214 00:19:11,250 --> 00:19:17,490 So our code replaces underscore m.jpeg, going back to the code. So it's replacing underscore m.jpeg 215 00:19:17,490 --> 00:19:23,340 with underscore b.jpeg in the photo url, to get the url for the larger image. 216 00:19:23,340 --> 00:19:29,220 And if we just have a look at Flickr photos, we've got a reference link here, that gives us a 217 00:19:29,220 --> 00:19:33,810 bit more information about Flickr photos. They are actually documented, 218 00:19:33,810 --> 00:19:39,150 you can see it talks about m being a small size and b being a large size, and because it is documented I think it should 219 00:19:39,150 --> 00:19:41,360 be pretty safe for us to use. 220 00:19:41,360 --> 00:19:48,270 Now going back to this code again here, this code relating to media files. That page is generated on 221 00:19:48,270 --> 00:19:52,300 Flickr servers, so it doesn't appear in the json data that we get back. 222 00:19:52,300 --> 00:19:58,820 So that's why we have to create it in our code, rather than just extracting it from the json data. OK, so now that 223 00:19:58,820 --> 00:20:04,470 we've got the data we want, in the next video we're going to go ahead and start creating photo objects. 224 00:20:04,470 --> 00:20:06,060 So I'll see you in the next video.