1 00:00:05,810 --> 00:00:11,240 Alright so moving on now, now that we've got the data we want, we're going to create a new photo object passing 2 00:00:11,240 --> 00:00:15,560 the values we've just extracted from the json data in the constructor. 3 00:00:15,560 --> 00:00:20,870 So the photo object can then be added to the list that we want, that we'll be returning, so I'd better declare 4 00:00:20,870 --> 00:00:23,810 an array list at the start of the function as well. This is the doInBackground, 5 00:00:23,810 --> 00:00:36,540 so let's do that, and I'll declare that under the log so we'll do a val photo list is equal to array list, 6 00:00:36,540 --> 00:00:43,360 diamond operator and it's going to be photo, so it's an array list of photo objects. 7 00:00:43,360 --> 00:00:50,800 And let's go ahead now and create an object, a photo object from the json data, so down here under 8 00:00:50,800 --> 00:01:07,870 the val link, we're going to put val photo object is equal to photo, parentheses title author author Id 9 00:01:07,870 --> 00:01:20,250 link tags and photoUrl. And because we've now got an array list we can do a photo list dot add 10 00:01:20,250 --> 00:01:26,090 photo object. Let's also do a log here, so Log.d 11 00:01:26,090 --> 00:01:37,790 parentheses tag comma dot doInBackground dollar photo object. So that's basically added logging there, 12 00:01:37,790 --> 00:01:43,130 at the end of the function to print out the data, just so we can check that everything's working as it should be. 13 00:01:43,130 --> 00:01:45,890 So the code will keep looping until it's processed 14 00:01:45,890 --> 00:01:51,500 all the items in the array, and we'll then end up with a list containing the details for each of the photos 15 00:01:51,500 --> 00:01:54,230 in the feed. So that's json passing. 16 00:01:54,230 --> 00:02:00,170 Now we haven't had to write a lot of code, and all the complexity of parsing json data is dealt with 17 00:02:00,170 --> 00:02:04,760 by the json objects in the org dot json package, which is pretty cool. 18 00:02:04,760 --> 00:02:11,860 So let's clear this error down here now, which relates to adding a catch block. So we're going to add a catch parentheses 19 00:02:11,860 --> 00:02:21,800 e colon JSONException, then a code block, and we'll start by doing a e.printStackTrace, then we'll do a Log dot 20 00:02:21,800 --> 00:02:32,420 e parentheses tag comma dot doInBackground, colon Error processing 21 00:02:32,420 --> 00:02:40,850 Json data dot, then we'll do a dollar, left and right curly braces e.dot message, which'll return the message passed by the 22 00:02:40,850 --> 00:02:48,530 json exception. And then we'll do, basically I'm going to cancel this one, so just a note here to cancel, 23 00:02:48,530 --> 00:02:51,430 true, because that's essentially what's going to happen, we're cancelling out of it. 24 00:02:51,430 --> 00:02:59,130 So do a listener dot onError parentheses e, parsing the actual error. 25 00:02:59,130 --> 00:03:04,940 So the catch block prints a stack trace with the code on line 47, then prints the message contained in an 26 00:03:04,940 --> 00:03:08,710 exception by calling its get message function. 27 00:03:08,710 --> 00:03:13,980 Now because our code's thrown an exception, we call the onError function of our listener 28 00:03:13,980 --> 00:03:17,220 to parse the exception back to the calling code. 29 00:03:17,220 --> 00:03:21,060 Now as I said earlier, this code's running on a separate thread. 30 00:03:21,060 --> 00:03:25,620 So that means that the calling code can't trap the exception using a try catch block, 31 00:03:25,620 --> 00:03:30,960 so we'll use this mechanism to let the caller know about any errors that may happen. 32 00:03:30,960 --> 00:03:36,800 Now I'm going to come back to this cancel true line that I've included as a comment a bit later. 33 00:03:36,800 --> 00:03:39,890 It'll makes sense when we've got the code running so I'll describe it then. 34 00:03:39,890 --> 00:03:44,880 Now the only other thing left to do is to return a list of photos that we've created. 35 00:03:44,880 --> 00:03:51,210 So let's go ahead and do that, and I'll get rid of that last error. First we'll do a log. so Log.d parentheses 36 00:03:51,210 --> 00:03:52,680 TAG comma, 37 00:03:52,680 --> 00:04:02,040 double quotes dot doInBackground ends, and then we'll do a return photo list. So that now clears the 38 00:04:02,040 --> 00:04:05,970 final error, because our function's now returning something. 39 00:04:05,970 --> 00:04:11,310 OK so when doInBackground finishes, the onPostExecute function will be called. 40 00:04:11,310 --> 00:04:15,450 So I'm going to use that to send the list of photos back to the calling code. 41 00:04:15,450 --> 00:04:18,279 So let's have a look at that, so onPostExecute. 42 00:04:18,279 --> 00:04:27,550 At the moment we've got the log and the super, so leave that in. On the next line we'll put Listener.onData 43 00:04:27,550 --> 00:04:36,540 Available, and in parentheses, result. Now we've got an error there, or I have anyway, you may not have. 44 00:04:36,540 --> 00:04:42,240 This function is declared to have a nullable parameter, and we've specified a not-nullable argument to 45 00:04:42,240 --> 00:04:47,740 onDataAvailable. Now we've already made sure that doInBackground can't return null, 46 00:04:47,740 --> 00:04:52,290 so it's OK to change the onPostExecute parameter to be non-nullable. 47 00:04:52,290 --> 00:04:57,510 So let's go ahead and do that. And then lastly we'll add some logging, so 48 00:04:57,510 --> 00:05:09,350 Log.d parentheses tag comma dot onPostExecute ends. 49 00:05:09,350 --> 00:05:13,410 Alright so that's how json parser finished. Now if everything worked, 50 00:05:13,410 --> 00:05:18,720 the calling class will have the photo list in it's onDataAvailable function, and can display 51 00:05:18,720 --> 00:05:21,480 the photos or do whatever else it wants with them. 52 00:05:21,480 --> 00:05:25,950 We can now get main activity to use this class to parse the data 53 00:05:25,950 --> 00:05:28,650 after get raw data's finished downloading it. 54 00:05:28,650 --> 00:05:35,580 So go back to main activity, so the place to perform the parsing's in the onDownloadComplete 55 00:05:35,580 --> 00:05:43,740 function, down here, and specifically if the status we got back is OK. 56 00:05:43,740 --> 00:05:47,220 So at the moment we're just adding some logging there. So now we're going to do 57 00:05:47,220 --> 00:05:58,310 val getFlickrJSONData is equal to GetFlickrJsonData parenthesis this, that's the listener 58 00:05:58,310 --> 00:06:08,240 again, then on the next line getFlickerJsonData.execute, and we're passing data. 59 00:06:08,240 --> 00:06:14,360 Now we've got this error because main activity isn't implementing the on data available interface yet. 60 00:06:14,360 --> 00:06:21,740 So let's do that, back up here to the class definition. So we've got AppCompactActivity comma get raw data dot on 61 00:06:21,740 --> 00:06:31,340 download complete. We also want to add, so comma onDataAvailable. 62 00:06:31,340 --> 00:06:36,570 OK so we've now got another error but we expected that. We're not yet implementing the required functions for 63 00:06:36,570 --> 00:06:37,830 this interface. 64 00:06:37,830 --> 00:06:47,430 So let's go down to the bottom and we'll get Android Studio to generate the stubs for us. 65 00:06:47,430 --> 00:06:52,160 Now the ones we want are relating to the onDataAvailable here, onDataAvailable and onError. 66 00:06:52,160 --> 00:07:00,350 So I'm going to select both of those, click OK, and by doing that we've removed that error. 67 00:07:00,350 --> 00:07:06,190 Now onDataAvailable will receive a list of photo objects, and we'll be using that list to display the 68 00:07:06,190 --> 00:07:07,780 details on the screen. 69 00:07:07,780 --> 00:07:11,940 For now though, we're just going to print the list so that we can see that everything's working. 70 00:07:11,940 --> 00:07:19,870 We'll also had the usual logging, so let's go ahead and do that. So for onDataAvailable, 71 00:07:19,870 --> 00:07:26,740 we're going to start with our log, the Log.d parenthesis TAG comma double quotes, dot onData 72 00:07:26,740 --> 00:07:36,560 Available called, data is dollar data. Then we'll just do a space there for future function. 73 00:07:36,560 --> 00:07:47,350 I'll do Log.d parentheses TAG comma double quotes dot onDataAvailable ends, and for onError, 74 00:07:47,350 --> 00:07:50,980 we're just going to do Log.d parentheses TAG comma on 75 00:07:50,980 --> 00:08:00,010 Error called with dollar, left and right curly braces, e dot, sorry, exception because exception's the name of the 76 00:08:00,010 --> 00:08:07,040 parameter exception dot message. Alright so let's look at this slide again. 77 00:08:07,040 --> 00:08:11,780 So you can see that MainActivity now implements two interface: the onDownloadComplete interface 78 00:08:11,780 --> 00:08:19,590 that's defined in GetRawData, and the onDataAvailable interface from our new GetFlickrJsonData class. 79 00:08:19,590 --> 00:08:25,920 Now the download started by creating a GetRawObject, or GetRawData object in onCreate. When the 80 00:08:25,920 --> 00:08:33,090 download completes, the onDownloadComplete function gets called. That kicks off parsing the data by creating 81 00:08:33,090 --> 00:08:35,610 a GetFlickrJsonData instance, 82 00:08:35,610 --> 00:08:41,580 and when the parsing completes, the onDataAvailable function gets called. Now we'll add the code to display 83 00:08:41,580 --> 00:08:42,929 the data later, 84 00:08:42,929 --> 00:08:48,390 so we still haven't implemented the left hand side of this diagram, but we have finished the classes on the 85 00:08:48,390 --> 00:08:50,130 right hand side now though. 86 00:08:50,130 --> 00:08:55,830 So at this point when we're ready to run the program and see if our parsing works. Alright, 87 00:08:55,830 --> 00:08:58,650 so let's now run this again and see if it works. 88 00:08:58,650 --> 00:09:09,040 So we're going to come up and start it, and actually what we should do is open log cat. And while I remember we've still 89 00:09:09,040 --> 00:09:14,080 got a filter on over here, so we can either take the filter off, or what we can do now that we've written 90 00:09:14,080 --> 00:09:18,350 the GetFlickrdjacentData class, we can add that to the filter so I think I might do that. 91 00:09:18,350 --> 00:09:26,710 So I'm going to add a pipe at the end of that, and do a getflickrjsondata, so we can also get output from 92 00:09:26,710 --> 00:09:30,130 that as well. And we can see that when I've done that, 93 00:09:30,130 --> 00:09:36,770 we've actually got an error here, system dot error. So something's actually crashed, and the error we've got back is 94 00:09:36,770 --> 00:09:41,200 'onError called with no value for m'. So that, I suspect, we know for sure now, 95 00:09:41,200 --> 00:09:44,950 it's relating to GetFlickrJsonData, the class doInBackground. 96 00:09:44,950 --> 00:09:48,100 So let's just go and have a look at that, 97 00:09:48,100 --> 00:09:53,140 and it's most likely something to do with retrieving the fields I would think. 98 00:09:53,140 --> 00:09:59,800 And this is a hint here, the fact that json media is never used. That tells me that I've made a typo, so 99 00:09:59,800 --> 00:10:04,880 I'm going to copy that, and that should have actually been here for the photo url. 100 00:10:04,880 --> 00:10:09,100 So we should have been using that, so we're retrieving the json object into json media. 101 00:10:09,100 --> 00:10:13,270 The photo is actually being extracted from json media. 102 00:10:13,270 --> 00:10:17,230 That's the correct way to do it so that should actually, hopefully, fix that problem. 103 00:10:17,230 --> 00:10:24,140 So let's run this again, I'll clear log cat. 104 00:10:24,140 --> 00:10:27,710 OK so we've got some different data this time, much better looking, 105 00:10:27,710 --> 00:10:30,920 and I think we might have fixed that problem. 106 00:10:30,920 --> 00:10:36,970 So if we scroll up and have a look first, we can see clearly here now that GetFlickrJsonData class is 107 00:10:36,970 --> 00:10:43,700 logging the data. So it's logging each photo as it's being parsed, and that's in it's doInBackground method as 108 00:10:43,700 --> 00:10:46,750 you can see there. It's printing it out, but if we go up further, 109 00:10:46,750 --> 00:10:51,190 we can see where the doInBackground was actually started. 110 00:10:51,190 --> 00:10:57,100 But in terms of the raw data itself, if you scroll up and have a look. If you recall we've got the raw 111 00:10:57,100 --> 00:11:01,270 json file that we downloaded, being logged in onDownloadComplete, 112 00:11:01,270 --> 00:11:06,790 but also if we scroll up and have a look, onPostExecute and GetRawData as well. 113 00:11:06,790 --> 00:11:11,620 So now that we can see that things are working, we're going to start commenting out that logging, but if we scroll it 114 00:11:11,620 --> 00:11:18,510 back down again, and have a look at our GetFlickrJsonData, the call, you can see doInBackground starts 115 00:11:18,510 --> 00:11:20,620 here. So that's from again, 116 00:11:20,620 --> 00:11:25,900 the GetFlickrJsonData class, and it's parsing each set of details for the photos. You can see that as 117 00:11:25,900 --> 00:11:31,990 it's doing that, we're getting each one logged, the information relating to the various fields, title, link and so 118 00:11:31,990 --> 00:11:34,670 on. So that's working nicely, so 119 00:11:34,670 --> 00:11:41,170 basically title, author, author Id, and link, and actually we can go right across, we can see tags as well. 120 00:11:41,170 --> 00:11:49,210 You can see the image there, we can see tags, all working nicely. 121 00:11:49,210 --> 00:11:56,420 So the parsing seems to be working, and when it completes, if we go right down to the end of the log, we've got the onDataAvailable 122 00:11:56,420 --> 00:11:58,320 function being called which is correct, 123 00:11:58,320 --> 00:12:04,370 and then onPostExecute actually ends right on the last line. Right, so at this point now that we've got the 124 00:12:04,370 --> 00:12:09,750 json data parsing correctly, we don't need to log the raw json data any more, so 125 00:12:09,750 --> 00:12:11,870 let's tidy up that log cat a little bit. 126 00:12:11,870 --> 00:12:15,600 So going back to, well we're in actually, MainActivity, so we'll stay in there, 127 00:12:15,600 --> 00:12:20,940 and what we'll do is we'll remove the data being logged in the onDownloadComplete function. 128 00:12:20,940 --> 00:12:25,220 So what I'm going to do is just remove this part here, 129 00:12:25,220 --> 00:12:29,080 so we've still got a message to say it's being called, but we just don't get the actual data. 130 00:12:29,080 --> 00:12:35,400 And I'll fix that, that's a typo, onDownloadComplete it should have been, not on completed, the name of the function. 131 00:12:35,400 --> 00:12:42,510 Right, so that's main activity, and the other thing is it's been logged in onPostExecute and get raw data. So lets 132 00:12:42,510 --> 00:12:47,910 also remove that from this line, this logging line, so that we don't see all that raw json data anymore, 133 00:12:47,910 --> 00:12:55,200 because we've confirmed that the json parser is working, and it's just basically making the log far too 134 00:12:55,200 --> 00:13:00,920 big for us to actually try and figure out, to make any sense of, so we're removing it from the log. 135 00:13:00,920 --> 00:13:07,770 Alright, we're going to run it again, and hopefully now the output will be a lot tidier. 136 00:13:07,770 --> 00:13:12,090 Alright, so you can see now that I've removed that raw data, things are a heck of a lot tidier than what they 137 00:13:12,090 --> 00:13:13,710 were before now. 138 00:13:13,710 --> 00:13:18,780 And we're still getting the function calls logged, so you can see the order that everything's happening. 139 00:13:18,780 --> 00:13:25,320 So the onCreate function in MainActivity creates a get raw data object to perform the downloading. 140 00:13:25,320 --> 00:13:32,040 Once the download's complete, the onPostExecute function, well that calls onDownloadComplete, and on 141 00:13:32,040 --> 00:13:33,060 DownloadComplete, 142 00:13:33,060 --> 00:13:39,180 actually here, you can see it here being called, that actually creates a GetFlickrJsonData object 143 00:13:39,180 --> 00:13:44,700 to parse the json into our list of photos, and we can see if I scroll down a little bit further, doInBackground starts. 144 00:13:44,700 --> 00:13:49,560 Then we can see each photo being created as it's going through the json data, 145 00:13:49,560 --> 00:13:57,130 and parsing it. And keep in mind here that when that's finished, the GetFlickrJsonData's onPostExecute should be called, 146 00:13:57,130 --> 00:14:00,660 and you can see that down there, it starts onPostExecute. 147 00:14:00,660 --> 00:14:03,480 And by the way the Android framework takes care of that. 148 00:14:03,480 --> 00:14:06,610 That's what the execute method of an async task does. 149 00:14:06,610 --> 00:14:09,590 So it runs the doInBackground function on a separate thread, 150 00:14:09,590 --> 00:14:12,630 then calls onPostExecute with the result. 151 00:14:12,630 --> 00:14:17,230 So onPostExecute then calls the onDataAvailable function in MainActivity that sends it 152 00:14:17,230 --> 00:14:18,260 the list of photos. 153 00:14:18,260 --> 00:14:20,180 So you can see all the photos in the list there, 154 00:14:20,180 --> 00:14:25,140 and that's because that's the array list we're printing out now. Instead of an individual list of photos that you just saw 155 00:14:25,140 --> 00:14:26,400 higher in the log, 156 00:14:26,400 --> 00:14:32,080 this is the complete list of photos in an array list being printed out. Alright so the last 157 00:14:32,080 --> 00:14:35,470 thing we want to do is to check what happens if there's an error, while parsing the data. 158 00:14:35,470 --> 00:14:41,120 Now I did have a typo anyway which actually caused that to actually error, before we actually fixed 159 00:14:41,120 --> 00:14:41,920 it earlier in this video, 160 00:14:41,920 --> 00:14:46,180 but let's just go through and show you how to simulate that and just check that 161 00:14:46,180 --> 00:14:51,790 what happens if we've got some invalid json data or if the json parser fails some reason. So we can 162 00:14:51,790 --> 00:14:53,860 go back to MainActivity to do that. 163 00:14:53,860 --> 00:15:00,460 That's the quickest way, and to duplicate the call, the execute, the GetFlickrJsonData.execute, duplicate that with 164 00:15:00,460 --> 00:15:07,000 command d, control d on a PC, and if you just send some, basically some bogus data in there, I'm just 165 00:15:07,000 --> 00:15:17,970 going to say bogus data. If we run that, and you can see we've got an error. 166 00:15:17,970 --> 00:15:24,820 Very similar error, or the actual log's very similar to what happened before I actually fixed the typo 167 00:15:24,820 --> 00:15:30,600 I made in GetFlickrJsonData. But you can see here it's actually saying what the 168 00:15:30,600 --> 00:15:35,320 actual error is, 'Error processing Json data. Value bogus of type java dot 169 00:15:35,320 --> 00:15:38,640 lang dot String cannot be converted to a JSON Object'. 170 00:15:38,640 --> 00:15:41,930 And again that's correct because it's not valid json data. 171 00:15:41,930 --> 00:15:44,160 So I'm getting the error log there. 172 00:15:44,160 --> 00:15:50,710 And also if you look further down, you can see that onError is also called, with the same message there. 173 00:15:50,710 --> 00:15:56,730 So we're basically seeing the log twice because the error is actually passed rather back to main activity in it's 174 00:15:56,730 --> 00:15:58,590 onError function. 175 00:15:58,590 --> 00:16:03,870 So that's why I may have passing rather an exception to the caller from code that's running on a separate thread. 176 00:16:03,870 --> 00:16:07,010 But there's a slight problem with this as we can see in the log cat. 177 00:16:07,010 --> 00:16:12,630 So even though we got an error while parsing the data, the onPostExecute method still gets called, 178 00:16:12,630 --> 00:16:17,460 so that in turn passes an empty list to onDataAvailable, and you can see this down here in this part 179 00:16:17,460 --> 00:16:19,290 of the log. 180 00:16:19,290 --> 00:16:21,810 Now we really don't want that to happen if there's an error. 181 00:16:21,810 --> 00:16:25,620 Now fortunately though the async task class has a way to prevent that. 182 00:16:25,620 --> 00:16:30,840 So async task will only call onPostExecute when doInBackground finishes. 183 00:16:30,840 --> 00:16:34,530 It won't do it, won't do that call if the task's cancelled. 184 00:16:34,530 --> 00:16:41,030 Now async task has a cancel method which lets the main thread cancel a long running task if necessary. 185 00:16:41,030 --> 00:16:46,350 Now we will be doing that later, when we look at how to handle the activity being destroyed by an 186 00:16:46,350 --> 00:16:52,350 orientation change. But there's no reason why an async task can't cancel itself though, 187 00:16:52,350 --> 00:16:55,760 and that seems like a good idea to do, if we get an error. 188 00:16:55,760 --> 00:17:04,400 So going back to GetFlickerJsonData, that's why we've got this cancel commented out code here, in the 189 00:17:04,400 --> 00:17:16,319 catch for the json exception errors. So I'm going to uncomment that line now, and just format it correctly. 190 00:17:16,319 --> 00:17:22,319 So if we cancel the task when there's an exception, the async task code won't call onPostExecute, which 191 00:17:22,319 --> 00:17:23,640 is what we want here. 192 00:17:23,640 --> 00:17:31,300 So let's just run the app again and confirm that that is the case, and that happens if there is an error. 193 00:17:31,300 --> 00:17:32,790 Open the log cat, 194 00:17:32,790 --> 00:17:35,880 and you can see that we've got a different result this time. Actually I might just clear the log and run it 195 00:17:35,880 --> 00:17:42,510 again, so we can see the fresh output, 196 00:17:42,510 --> 00:17:46,040 and that looks better as you can see. We get the exception message logged by 197 00:17:46,040 --> 00:17:49,220 the GetFlickrJsonData dot onPostExecute, 198 00:17:49,220 --> 00:17:54,890 and again by MainActivity onDownloadComplete, and then MainActivity onError, 199 00:17:54,890 --> 00:18:01,310 but then the doInBackground actually ends down here as you can see, after showing the actual errors. 200 00:18:01,310 --> 00:18:05,740 So basically onPostExecute doesn't get called in that scenario, and MainActivity doesn't have to then 201 00:18:05,740 --> 00:18:09,980 deal with an empty list. Alright so that's our two async tasks 202 00:18:09,980 --> 00:18:13,450 now working. What I'll do before we end the video is I'll go back to MainActivity. 203 00:18:13,450 --> 00:18:16,680 I'm going to fix this line here. I'm 204 00:18:16,680 --> 00:18:21,290 actually just going to delete that line entirely, and uncomment the previous line so we've got some valid 205 00:18:21,290 --> 00:18:24,140 data when we actually start the next video. 206 00:18:24,140 --> 00:18:28,250 So I'll stop the video now and in the next one we're going to sort out the url so that we can add the 207 00:18:28,250 --> 00:18:32,900 tag parameters to it, and that's going to allow us to return data for different searches. 208 00:18:32,900 --> 00:18:34,060 So I'll see you in the next video.