1 00:00:04,160 --> 00:00:06,600 Alright, so let's now run the app and 2 00:00:06,600 --> 00:00:09,510 see if it works, and I'm going to open 3 00:00:09,510 --> 00:00:11,759 logcat. I'm gonna make sure that I've 4 00:00:11,759 --> 00:00:14,309 still got my filter set mainactivity 5 00:00:14,309 --> 00:00:17,279 pipe downdata, which I have, and I've 6 00:00:17,279 --> 00:00:19,289 also got Regex checked as well, 7 00:00:19,289 --> 00:00:21,779 which would be the default. Now, as long 8 00:00:21,779 --> 00:00:23,070 as I haven't left the emulator in 9 00:00:23,070 --> 00:00:25,170 airplane mode, it should all work. I'm 10 00:00:25,170 --> 00:00:26,160 going to clear - well I don't need to 11 00:00:26,160 --> 00:00:27,869 clear the logcat first because it is 12 00:00:27,869 --> 00:00:31,109 clear, but if not, do so - and we'll run it and 13 00:00:31,109 --> 00:00:35,340 see what happens. And we'll tab over to 14 00:00:35,340 --> 00:00:43,680 our app. And that doesn't look good. 15 00:00:43,680 --> 00:00:46,739 There's no XML being logged and also no 16 00:00:46,739 --> 00:00:48,930 stack trace to give us any indication of 17 00:00:48,930 --> 00:00:50,760 what's gone wrong. Now there are 18 00:00:50,760 --> 00:00:53,430 two errors, as we can see here, showing up 19 00:00:53,430 --> 00:00:56,010 from MainActivity. And if we click on 20 00:00:56,010 --> 00:01:00,989 the top one - the top error here - that 21 00:01:00,989 --> 00:01:03,180 takes us to, as you can see, our onPost 22 00:01:03,180 --> 00:01:06,570 Execute function, and to the call to the 23 00:01:06,570 --> 00:01:09,150 parseApplications.parse function call. 24 00:01:09,150 --> 00:01:11,460 So with just that information in the 25 00:01:11,460 --> 00:01:13,470 logcat, things like this can be really 26 00:01:13,470 --> 00:01:16,740 hard to debug, but fortunately, that isn't 27 00:01:16,740 --> 00:01:18,930 all that's available. The problem is, and 28 00:01:18,930 --> 00:01:20,520 I alluded to that, is that we're 29 00:01:20,520 --> 00:01:22,619 filtering the logcat, and that means that 30 00:01:22,619 --> 00:01:24,360 we don't see any entries being logged, 31 00:01:24,360 --> 00:01:27,000 unless they come from MainActivity or 32 00:01:27,000 --> 00:01:29,490 from DownloadData. So I'm going to click 33 00:01:29,490 --> 00:01:31,350 on this little x here to clear the 34 00:01:31,350 --> 00:01:33,659 filter window, and once I do that - well to 35 00:01:33,659 --> 00:01:35,310 clear the filter rather - and once I do 36 00:01:35,310 --> 00:01:36,689 that, you can see that we've got the 37 00:01:36,689 --> 00:01:39,270 complete log. Now that's actually gonna 38 00:01:39,270 --> 00:01:41,369 give us far more to go on, so remember 39 00:01:41,369 --> 00:01:44,310 that. If you filter the logcat, make sure 40 00:01:44,310 --> 00:01:45,780 you clear the filters when your app 41 00:01:45,780 --> 00:01:46,320 crashes, 42 00:01:46,320 --> 00:01:48,000 otherwise, you'll be trying to find the 43 00:01:48,000 --> 00:01:49,770 cause of the crash with very little 44 00:01:49,770 --> 00:01:51,000 information to go on. 45 00:01:51,000 --> 00:01:53,700 Now before we cleared the filter, there 46 00:01:53,700 --> 00:01:55,560 was nothing to indicate that parse was 47 00:01:55,560 --> 00:01:57,869 even being called. Now that could have 48 00:01:57,869 --> 00:02:00,149 caused a lot of confusion when trying to 49 00:02:00,149 --> 00:02:02,520 debug this. So now that we've cleared the 50 00:02:02,520 --> 00:02:05,250 filter, we can see, if we scroll up and have a 51 00:02:05,250 --> 00:02:08,128 bit of a look here, or we can actually 52 00:02:08,128 --> 00:02:10,318 see anyway - we can see that parse clearly 53 00:02:10,318 --> 00:02:11,520 has logged the XML because that was 54 00:02:11,520 --> 00:02:13,080 showing as soon as I cleared the filter. 55 00:02:13,080 --> 00:02:13,650 And 56 00:02:13,650 --> 00:02:15,090 we can also see, if we scroll down and 57 00:02:15,090 --> 00:02:16,920 have a bit of a look here, that the 58 00:02:16,920 --> 00:02:22,739 actual error is here on line 29: null 59 00:02:22,739 --> 00:02:25,290 cannot be cast to non-null type Java dot 60 00:02:25,290 --> 00:02:26,610 lang.String. So I'm gonna click on that, 61 00:02:26,610 --> 00:02:30,720 and that takes us to the line that's got 62 00:02:30,720 --> 00:02:32,700 the TODO that I talked about, in the 63 00:02:32,700 --> 00:02:35,129 previous video. So the error in the 64 00:02:35,129 --> 00:02:37,620 logcat was kotlin.TypeCastException, 65 00:02:37,620 --> 00:02:40,140 and you can see this on screen: null cannot 66 00:02:40,140 --> 00:02:43,079 be cast to non-null type java.lang 67 00:02:43,079 --> 00:02:46,230 dot String. So what that essentially means is 68 00:02:46,230 --> 00:02:48,180 that we're trying to call the toLowercase 69 00:02:48,180 --> 00:02:51,900 method on a value that's null. Now xpp 70 00:02:51,900 --> 00:02:54,690 dot name starts off null until something's 71 00:02:54,690 --> 00:02:56,940 being read, and null doesn't have any 72 00:02:56,940 --> 00:02:59,760 properties or methods. So to fix the 73 00:02:59,760 --> 00:03:02,250 problem, we're going to use the safe call 74 00:03:02,250 --> 00:03:04,470 operator that we've used before, and it 75 00:03:04,470 --> 00:03:06,269 makes sure that we don't attempt to call 76 00:03:06,269 --> 00:03:08,489 methods on things that are null. So all 77 00:03:08,489 --> 00:03:10,560 we really need to do here, is actually, 78 00:03:10,560 --> 00:03:13,680 after the xpp.name - we're going to 79 00:03:13,680 --> 00:03:17,489 put a question mark after that, and then I'm 80 00:03:17,489 --> 00:03:18,810 going to remove the TODO because we've, 81 00:03:18,810 --> 00:03:22,410 effectively, fixed that now. If we run 82 00:03:22,410 --> 00:03:29,010 this again, this time we're actually 83 00:03:29,010 --> 00:03:31,500 getting our formatted data showing in 84 00:03:31,500 --> 00:03:33,030 the logcat, so clearly that was the issue 85 00:03:33,030 --> 00:03:35,549 that we've managed to fix. So if we 86 00:03:35,549 --> 00:03:37,079 scroll back now up to the start of the 87 00:03:37,079 --> 00:03:41,549 log, we can see this onCreate starting 88 00:03:41,549 --> 00:03:43,729 and then there's doinBackground: starts. 89 00:03:43,729 --> 00:03:46,109 We've got a response code of two 90 00:03:46,109 --> 00:03:51,790 hundred, and if we scroll down a bit further, 91 00:03:51,790 --> 00:03:54,019 then you can see that the parser is 92 00:03:54,019 --> 00:03:57,470 logging the XML that it receives. And 93 00:03:57,470 --> 00:03:58,580 that's working just like it did before, 94 00:03:58,580 --> 00:04:00,739 but after that, if we keep scrolling down 95 00:04:00,739 --> 00:04:03,700 again now, past the XML, we can see that 96 00:04:03,700 --> 00:04:06,560 the log entries from our parse method 97 00:04:06,560 --> 00:04:08,450 showing here; Starting tag for feed, 98 00:04:08,450 --> 00:04:11,030 Starting tag for ID, Ending tag for ID, 99 00:04:11,030 --> 00:04:13,159 and so on. So, every time there was a 100 00:04:13,159 --> 00:04:15,200 START_TAG or END_ 101 00:04:15,200 --> 00:04:17,389 TAG event, it got logged. So the 102 00:04:17,389 --> 00:04:18,949 logcat's showing the name of each tag 103 00:04:18,949 --> 00:04:22,100 in the XML, as the PullParser sets event 104 00:04:22,100 --> 00:04:24,770 type to START_TAG and END 105 00:04:24,770 --> 00:04:27,500 _TAG. Now if we scroll down 106 00:04:27,500 --> 00:04:32,720 round about 20 or so lines down, we get 107 00:04:32,720 --> 00:04:35,479 over here, the Starting tag for entry. So 108 00:04:35,479 --> 00:04:37,160 from there to the end of the entry tag, 109 00:04:37,160 --> 00:04:38,630 the code's looking for the tags we're 110 00:04:38,630 --> 00:04:40,820 interested in, and storing their values 111 00:04:40,820 --> 00:04:43,550 in the FeedEntry object. Now we can make 112 00:04:43,550 --> 00:04:44,750 life a little bit easier by using 113 00:04:44,750 --> 00:04:47,139 control F, or command F on a Mac, to 114 00:04:47,139 --> 00:04:50,539 search the logcat for entry. So I'll do 115 00:04:50,539 --> 00:04:56,030 that - entry. When I press ENTER, it jumps 116 00:04:56,030 --> 00:04:57,680 to the first, it'll actually jump 117 00:04:57,680 --> 00:04:59,630 to the first occurrence automatically. But if 118 00:04:59,630 --> 00:05:02,750 I press ENTER, it should jump to an 119 00:05:02,750 --> 00:05:04,430 occurrence of entry that's in the XML at 120 00:05:04,430 --> 00:05:06,440 the top, and I can use the down arrow on 121 00:05:06,440 --> 00:05:08,510 the toolbar to jump to the next one. So 122 00:05:08,510 --> 00:05:10,039 come over here and go down to the next one, 123 00:05:10,039 --> 00:05:14,300 and I can also use this little plus 124 00:05:14,300 --> 00:05:16,970 button over here, to highlight all the 125 00:05:16,970 --> 00:05:19,610 places where entry appears. And then they 126 00:05:19,610 --> 00:05:21,139 will stay highlighted, as long as I don't 127 00:05:21,139 --> 00:05:23,330 close the search pane, and that's great 128 00:05:23,330 --> 00:05:24,590 for scrolling up and down the logcat, 129 00:05:24,590 --> 00:05:26,240 seeing where the entries start and end. So 130 00:05:26,240 --> 00:05:30,039 I'll click on that, and scroll up and down, 131 00:05:30,039 --> 00:05:32,210 and you can see entries highlighted 132 00:05:32,210 --> 00:05:35,270 there for us automatically, which is pretty 133 00:05:35,270 --> 00:05:38,360 cool. So the parser is going 134 00:05:38,360 --> 00:05:41,360 through the entire XML stream, responding 135 00:05:41,360 --> 00:05:43,099 to the information it finds in there. 136 00:05:43,099 --> 00:05:45,949 Now our code's checking to see where the 137 00:05:45,949 --> 00:05:48,380 new tag's found, and when it ends, and 138 00:05:48,380 --> 00:05:51,470 pulling out the values we need. Now most 139 00:05:51,470 --> 00:05:53,330 of the tags start and end straight away, 140 00:05:53,330 --> 00:05:56,570 but when we get an entry tag starting, we 141 00:05:56,570 --> 00:05:58,699 stay in the entry because all the other 142 00:05:58,699 --> 00:06:01,130 tags are nested inside it. And once it's 143 00:06:01,130 --> 00:06:03,620 gone through updated, ID, title and so on - 144 00:06:03,620 --> 00:06:05,479 processing all those tags - 145 00:06:05,479 --> 00:06:07,669 it eventually gets the closing tag for 146 00:06:07,669 --> 00:06:10,460 entry. There's releasedate and content, 147 00:06:10,460 --> 00:06:12,830 and then we get the end tag for entry. So 148 00:06:12,830 --> 00:06:13,969 you can see that, as we're going down 149 00:06:13,969 --> 00:06:16,039 here, the starting tag, all the various 150 00:06:16,039 --> 00:06:18,750 tags there, 151 00:06:18,750 --> 00:06:20,680 releasedate, as I said there, and 152 00:06:20,680 --> 00:06:22,660 eventually the tag, ending tag for 153 00:06:22,660 --> 00:06:24,759 content and then ending tag for entry, 154 00:06:24,759 --> 00:06:26,699 and then we've got another one starting. 155 00:06:26,699 --> 00:06:29,440 So once we get the end tag for an entry, 156 00:06:29,440 --> 00:06:31,300 we know that all its fields have been 157 00:06:31,300 --> 00:06:33,849 processed and we can add the object to 158 00:06:33,849 --> 00:06:36,310 the list. And that's why most of the code 159 00:06:36,310 --> 00:06:38,590 does its processing when we get to the 160 00:06:38,590 --> 00:06:41,020 END_TAG events. In other words, 161 00:06:41,020 --> 00:06:43,750 that's why we added a lot of coding in 162 00:06:43,750 --> 00:06:46,449 this particular area - the END 163 00:06:46,449 --> 00:06:49,319 _TAG tag, if that makes sense. 164 00:06:49,319 --> 00:06:51,819 So what I can also do is come over here, 165 00:06:51,819 --> 00:06:54,400 to the find, and instead of just leaving 166 00:06:54,400 --> 00:06:56,110 entry in there, I can actually put a pipe 167 00:06:56,110 --> 00:06:59,500 and a name as well. And I still want to 168 00:06:59,500 --> 00:07:00,580 make sure that the Regex 169 00:07:00,580 --> 00:07:02,530 checkbox is checked, but this time it's 170 00:07:02,530 --> 00:07:04,300 the regex that's appropriate for the 171 00:07:04,300 --> 00:07:08,199 search, not the regex for our filter. And you 172 00:07:08,199 --> 00:07:09,759 can see now that it highlights - just 173 00:07:09,759 --> 00:07:11,590 scroll down the file a little bit more, 174 00:07:11,590 --> 00:07:15,219 so we can see it a bit better - it's 175 00:07:15,219 --> 00:07:17,379 highlighting both name and entry because 176 00:07:17,379 --> 00:07:19,780 we've used the pipe to be able to search 177 00:07:19,780 --> 00:07:21,789 for either of those. Now I've done that 178 00:07:21,789 --> 00:07:23,560 to show why we keep track of when we're 179 00:07:23,560 --> 00:07:25,810 inside an entry tag, so I'm scrolling 180 00:07:25,810 --> 00:07:28,330 back up - scroll right back until we get 181 00:07:28,330 --> 00:07:31,039 to the first entry. 182 00:07:31,039 --> 00:07:34,309 So there's the first entry, so if we keep 183 00:07:34,309 --> 00:07:36,319 scrolling back up to the top, to our 184 00:07:36,319 --> 00:07:39,139 very first entry. 185 00:07:39,139 --> 00:07:43,129 Alright, so our first entry is here, but 186 00:07:43,129 --> 00:07:45,080 you see above that, there's a name tag 187 00:07:45,080 --> 00:07:46,909 that's not part of that first entry 188 00:07:46,909 --> 00:07:48,620 there. But we don't want to use that name - 189 00:07:48,620 --> 00:07:50,960 it's the name of the whole feed, not one 190 00:07:50,960 --> 00:07:53,150 of the individual applications. So 191 00:07:53,150 --> 00:07:54,919 because we only use the tag values if 192 00:07:54,919 --> 00:07:57,590 inEntry is true, the code will ignore 193 00:07:57,590 --> 00:07:59,719 this one. Alright, now if we scroll down 194 00:07:59,719 --> 00:08:02,389 to the bottom here, we can see the 195 00:08:02,389 --> 00:08:03,979 summary of the application records that 196 00:08:03,979 --> 00:08:07,189 we've created, as well. So there should be 197 00:08:07,189 --> 00:08:09,379 ten applications there, because we chose 198 00:08:09,379 --> 00:08:11,659 the Top 10 feed, and we can see the data 199 00:08:11,659 --> 00:08:13,969 nicely formatted into the individual 200 00:08:13,969 --> 00:08:17,629 feeds. Now one thing I want to mention is 201 00:08:17,629 --> 00:08:20,719 the imageURL. There are actually three 202 00:08:20,719 --> 00:08:23,150 image tags in each entry, and our code 203 00:08:23,150 --> 00:08:25,340 picks up the value of each one, then 204 00:08:25,340 --> 00:08:27,139 overrides it when the next one comes 205 00:08:27,139 --> 00:08:29,569 around. Because the image tags appear in 206 00:08:29,569 --> 00:08:32,179 size order in the XML, we end up with the 207 00:08:32,179 --> 00:08:35,719 URLs for the 100 by 100 image. But you 208 00:08:35,719 --> 00:08:37,279 shouldn't really rely on the ordering of 209 00:08:37,279 --> 00:08:40,099 tags in an XML feed. The XML would have 210 00:08:40,099 --> 00:08:42,589 been invalid, whatever order the 211 00:08:42,589 --> 00:08:45,230 image URLs had appeared. So going back to 212 00:08:45,230 --> 00:08:48,339 Chrome, and if we look for those images - 213 00:08:48,339 --> 00:08:53,000 so look for image - you'll notice here, 214 00:08:53,000 --> 00:08:54,550 that the image has got a height 215 00:08:54,550 --> 00:08:57,500 attribute. So if we were interested in a 216 00:08:57,500 --> 00:08:59,510 particular image size, we could check 217 00:08:59,510 --> 00:09:01,640 that attribute and only store the URL 218 00:09:01,640 --> 00:09:04,790 for the height we wanted. But I'm not 219 00:09:04,790 --> 00:09:06,260 going to check the attributes in this 220 00:09:06,260 --> 00:09:07,970 code, because it'll make it too 221 00:09:07,970 --> 00:09:10,220 specific to these Apple feeds, and you 222 00:09:10,220 --> 00:09:11,240 may want to experiment with different 223 00:09:11,240 --> 00:09:14,089 feeds. But if you really want to test the 224 00:09:14,089 --> 00:09:16,399 attributes, you'd usually get attribute 225 00:09:16,399 --> 00:09:18,380 value function of the PullParser, and 226 00:09:18,380 --> 00:09:20,420 you can search online for ways to do 227 00:09:20,420 --> 00:09:22,640 that. Now I'm going to pop up a slide for a 228 00:09:22,640 --> 00:09:24,890 few seconds, showing the changes I made 229 00:09:24,890 --> 00:09:27,079 to test the height attribute, and load 230 00:09:27,079 --> 00:09:28,790 the small imageURL - the one with the height 231 00:09:28,790 --> 00:09:31,040 of 53. So if you want to choose a 232 00:09:31,040 --> 00:09:33,199 specific image and get stuck, you can 233 00:09:33,199 --> 00:09:36,610 refer to this slide for one way to do it. 234 00:09:36,610 --> 00:09:39,079 Alright, so that's our application - 235 00:09:39,079 --> 00:09:41,000 downloading the feed and parsing out the 236 00:09:41,000 --> 00:09:43,910 information we're interested. The next 237 00:09:43,910 --> 00:09:45,940 step, now, is to display it on the screen. 238 00:09:45,940 --> 00:09:48,740 Now we could add ten TextView widgets to 239 00:09:48,740 --> 00:09:50,779 the screen, and put the details of each 240 00:09:50,779 --> 00:09:52,160 application in them, 241 00:09:52,160 --> 00:09:53,660 but then the app wouldn't work for the 242 00:09:53,660 --> 00:09:56,690 Top 25 feed, or for other feeds that could 243 00:09:56,690 --> 00:09:59,209 return, perhaps, hundreds of records. So in 244 00:09:59,209 --> 00:10:00,709 the next few videos, we're gonna look at 245 00:10:00,709 --> 00:10:02,420 one way of dealing with displaying data 246 00:10:02,420 --> 00:10:04,430 when you don't know, in advance, how many 247 00:10:04,430 --> 00:10:07,370 records it's going to be. So, as always, I'll 248 00:10:07,370 --> 00:10:10,389 see you in the next video.