Alright, so let's now run the app and
see if it works, and I'm going to open
logcat. I'm gonna make sure that I've
still got my filter set mainactivity
pipe downdata, which I have, and I've
also got Regex checked as well,
which would be the default. Now, as long
as I haven't left the emulator in
airplane mode, it should all work. I'm
going to clear - well I don't need to
clear the logcat first because it is
clear, but if not, do so - and we'll run it and
see what happens. And we'll tab over to
our app. And that doesn't look good.
There's no XML being logged and also no
stack trace to give us any indication of
what's gone wrong. Now there are
two errors, as we can see here, showing up
from MainActivity. And if we click on
the top one - the top error here - that
takes us to, as you can see, our onPost
Execute function, and to the call to the
parseApplications.parse function call.
So with just that information in the
logcat, things like this can be really
hard to debug, but fortunately, that isn't
all that's available. The problem is, and
I alluded to that, is that we're
filtering the logcat, and that means that
we don't see any entries being logged,
unless they come from MainActivity or
from DownloadData. So I'm going to click
on this little x here to clear the
filter window, and once I do that - well to
clear the filter rather - and once I do
that, you can see that we've got the
complete log. Now that's actually gonna
give us far more to go on, so remember
that. If you filter the logcat, make sure
you clear the filters when your app
crashes,
otherwise, you'll be trying to find the
cause of the crash with very little
information to go on.
Now before we cleared the filter, there
was nothing to indicate that parse was
even being called. Now that could have
caused a lot of confusion when trying to
debug this. So now that we've cleared the
filter, we can see, if we scroll up and have a
bit of a look here, or we can actually
see anyway - we can see that parse clearly
has logged the XML because that was
showing as soon as I cleared the filter.
And
we can also see, if we scroll down and
have a bit of a look here, that the
actual error is here on line 29: null
cannot be cast to non-null type Java dot
lang.String. So I'm gonna click on that,
and that takes us to the line that's got
the TODO that I talked about, in the
previous video. So the error in the
logcat was kotlin.TypeCastException,
and you can see this on screen: null cannot
be cast to non-null type java.lang
dot String. So what that essentially means is
that we're trying to call the toLowercase
method on a value that's null. Now xpp
dot name starts off null until something's
being read, and null doesn't have any
properties or methods. So to fix the
problem, we're going to use the safe call
operator that we've used before, and it
makes sure that we don't attempt to call
methods on things that are null. So all
we really need to do here, is actually,
after the xpp.name - we're going to
put a question mark after that, and then I'm
going to remove the TODO because we've,
effectively, fixed that now. If we run
this again, this time we're actually
getting our formatted data showing in
the logcat, so clearly that was the issue
that we've managed to fix. So if we
scroll back now up to the start of the
log, we can see this onCreate starting
and then there's doinBackground: starts.
We've got a response code of two
hundred, and if we scroll down a bit further,
then you can see that the parser is
logging the XML that it receives. And
that's working just like it did before,
but after that, if we keep scrolling down
again now, past the XML, we can see that
the log entries from our parse method
showing here; Starting tag for feed,
Starting tag for ID, Ending tag for ID,
and so on. So, every time there was a
START_TAG or END_
TAG event, it got logged. So the
logcat's showing the name of each tag
in the XML, as the PullParser sets event
type to START_TAG and END
_TAG. Now if we scroll down
round about 20 or so lines down, we get
over here, the Starting tag for entry. So
from there to the end of the entry tag,
the code's looking for the tags we're
interested in, and storing their values
in the FeedEntry object. Now we can make
life a little bit easier by using
control F, or command F on a Mac, to
search the logcat for entry. So I'll do
that - entry. When I press ENTER, it jumps
to the first, it'll actually jump
to the first occurrence automatically. But if
I press ENTER, it should jump to an
occurrence of entry that's in the XML at
the top, and I can use the down arrow on
the toolbar to jump to the next one. So
come over here and go down to the next one,
and I can also use this little plus
button over here, to highlight all the
places where entry appears. And then they
will stay highlighted, as long as I don't
close the search pane, and that's great
for scrolling up and down the logcat,
seeing where the entries start and end. So
I'll click on that, and scroll up and down,
and you can see entries highlighted
there for us automatically, which is pretty
cool. So the parser is going
through the entire XML stream, responding
to the information it finds in there.
Now our code's checking to see where the
new tag's found, and when it ends, and
pulling out the values we need. Now most
of the tags start and end straight away,
but when we get an entry tag starting, we
stay in the entry because all the other
tags are nested inside it. And once it's
gone through updated, ID, title and so on -
processing all those tags -
it eventually gets the closing tag for
entry. There's releasedate and content,
and then we get the end tag for entry. So
you can see that, as we're going down
here, the starting tag, all the various
tags there,
releasedate, as I said there, and
eventually the tag, ending tag for
content and then ending tag for entry,
and then we've got another one starting.
So once we get the end tag for an entry,
we know that all its fields have been
processed and we can add the object to
the list. And that's why most of the code
does its processing when we get to the
END_TAG events. In other words,
that's why we added a lot of coding in
this particular area - the END
_TAG tag, if that makes sense.
So what I can also do is come over here,
to the find, and instead of just leaving
entry in there, I can actually put a pipe
and a name as well. And I still want to
make sure that the Regex
checkbox is checked, but this time it's
the regex that's appropriate for the
search, not the regex for our filter. And you
can see now that it highlights - just
scroll down the file a little bit more,
so we can see it a bit better - it's
highlighting both name and entry because
we've used the pipe to be able to search
for either of those. Now I've done that
to show why we keep track of when we're
inside an entry tag, so I'm scrolling
back up - scroll right back until we get
to the first entry.
So there's the first entry, so if we keep
scrolling back up to the top, to our
very first entry.
Alright, so our first entry is here, but
you see above that, there's a name tag
that's not part of that first entry
there. But we don't want to use that name -
it's the name of the whole feed, not one
of the individual applications. So
because we only use the tag values if
inEntry is true, the code will ignore
this one. Alright, now if we scroll down
to the bottom here, we can see the
summary of the application records that
we've created, as well. So there should be
ten applications there, because we chose
the Top 10 feed, and we can see the data
nicely formatted into the individual
feeds. Now one thing I want to mention is
the imageURL. There are actually three
image tags in each entry, and our code
picks up the value of each one, then
overrides it when the next one comes
around. Because the image tags appear in
size order in the XML, we end up with the
URLs for the 100 by 100 image. But you
shouldn't really rely on the ordering of
tags in an XML feed. The XML would have
been invalid, whatever order the
image URLs had appeared. So going back to
Chrome, and if we look for those images -
so look for image - you'll notice here,
that the image has got a height
attribute. So if we were interested in a
particular image size, we could check
that attribute and only store the URL
for the height we wanted. But I'm not
going to check the attributes in this
code, because it'll make it too
specific to these Apple feeds, and you
may want to experiment with different
feeds. But if you really want to test the
attributes, you'd usually get attribute
value function of the PullParser, and
you can search online for ways to do
that. Now I'm going to pop up a slide for a
few seconds, showing the changes I made
to test the height attribute, and load
the small imageURL - the one with the height
of 53. So if you want to choose a
specific image and get stuck, you can
refer to this slide for one way to do it.
Alright, so that's our application -
downloading the feed and parsing out the
information we're interested. The next
step, now, is to display it on the screen.
Now we could add ten TextView widgets to
the screen, and put the details of each
application in them,
but then the app wouldn't work for the
Top 25 feed, or for other feeds that could
return, perhaps, hundreds of records. So in
the next few videos, we're gonna look at
one way of dealing with displaying data
when you don't know, in advance, how many
records it's going to be. So, as always, I'll
see you in the next video.