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.

