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.

