Alright, so this bit about the Reader
can be important. Now if you remember, we
were discussing huge files a few videos
ago. In this app, we're reading the entire
XML into one string. But the XMLPull
Parser's quite happy to be given a Reader,
and to process the data as it comes down
from the internet. Now the PullParser
doesn't hang on to text that it's
already processed - it just throws it away.
So if you did want to process gigabytes
of RSS on an Android device, you could
connect the Reader to the input stream,
instead of providing the entire string.
Now of course, if your users are paying
to download data, then they may not be too
impress downloading that data on a
mobile data plan. So there are other
things to consider, in addition to the
memory on the device, but the options are
available if you need them. Okay, so
as the PullParser processes its
input, various events will happen. Now
this will be things like entering a tag
or reaching the end of the document. Now
we can get those events and respond to
them in our code. So the first thing we
do is check the event, and make sure that
we haven't reached the end of the
document - the end of the XML, that is -
that's this code here on line 28. Now if
we haven't then, of course, we shouldn't
have unless the XML was empty. Then the
while loop will keep looping until we do
get to the end. Now inside the loop is
where we get the values of the fields
we're interested in. As long as we check
the event type each time around, we can
just keep checking for the tags we want,
until there's no more XML left. So let's
go ahead and write some more code now. So
we've got the code there for checking, to
see whether we've reached the end of the
document. So within the while loop, we're now
going to type in the code; val tagName
is equal to xpp.name dot to
Lowercase. And I'm just going to put a
comment here, as a TODO: we should use
the safe call operator, and more on that
later. So on the next line, we're going to do
when
parentheses eventType and open the code
block. I'm going to start with the first
one which will be XmlPullParser dot
START_TAG. So we need to add
our arrow there, and a code block. Then we'll
do a Log.d for starters, TAG comma
and then double quotes, parse colon
Starting tag for, and then + tagName.
Then if, parentheses, tagName is equal
equal to entry, in lowercase - again, we're
opening a code block. That's going to be
inEntry equals true. Then outside of the
code block, we're just finishing off
those two tags. So we've got the
ending tag for the if and then the
ending tag for the XmlPullParser dot
START_TAG. So after that, the next one to
check will be XmlPullParser.TEXT. Then
I'm going to use an arrow again, and it's
going to be textValue equals xpp dot
text. Next, we're going to do XmlPull
Parser.END_TAG, then arrow again.
And then we need a code block for
that, and let's add a log first, so Log
dot d again, and the log's going to be
TAG in parentheses, and the second
argument after the comma is parse: Ending tag
for + tagName. Then next line, if
parenthesis in Entry parenthesis, then
when parentheses tagName, then open a
code block. I'm gonna start with entry
in double quotes, then arrow and open a
code block. Then we're gonna do applications
dot addCurrentRecord and set inEntry
to false, so inEntry equals false.
Then currentRecord, we're gonna
set to a new object - FeedEntry. So we
create a new object, just to be clear
what we're doing that for. Now I need a
parentheses after FeedEntry there,
because we are creating a new object.
Okay, then we're closing off that when,
or the first condition, which is
entry. The next one we're going to test
is name, so name in double quotes, arrow.
We're going to set currentRecord.name to
equal textValue. Next, artist in double
quotes, lower case, arrow currentRecord dot
artist equals textValue. Next, in double
quotes, is releaseDate arrow current
Record.releaseDate is equal to text
Value. Two more; summary and double quotes
arrow currentRecord.summary is
equal to textValue, and the last one
will be image, and that's going to be current
record.imageURL is equal to text
Value. Okay. And the other thing we need to do
outside of this loop here, down here - we're
going to put Nothing else to do, so we're
going to put eventType equals xpp dot
next. So I'm going to move on to the next
one.
Okay. Now inside the while loop that
we've just created, we start off by
getting the name of the current tag, and
that's this one here - the code on line
29. We do that each time around the loop,
and it's worth noting that name can be
null, if the parser isn't inside a tag. Now
we should use the safe call operator
there, but I want to show you something
confusing about the logcat,
so I'll left it out. There's a TODO
command so I don't forget to add it in
later. Now, we can then take different
action, depending on the type of event
that's happened inside the parser. At
some point, it's going to read the start
of a tag in the XML, so when that happens,
the event type will actually change to
START_TAG, as you can see here. So if that
happens, we're only interested IF it's an
entry tag, because we're only doing
anything with the data in the individual
entries. Now you could if you wanted,
modify this slightly, so it displays the
title of the feed, but we're not going to
do that. At least, I'm not going to do it,
but it would make a good challenge so
you never know.
Alright. So if we have got an entry tag,
we set inEntry to true. You can see that
here - the code on line 35. Now as long as
inEntry is true, we know we can use the
data for the tags we're interested in.
Now at the end of the loop, we
check the next event by calling the
PullParser's next method - this one down
here, on line 62. Now that basically tells
the parser to continue working through
the XML until the next interesting thing
happens. Now that could be it finds an
end tag or it finds a value in the tag,
it reaches the end of the document or so
on. We don't know what the next event
will be, but as long as it's not the end
of the document, we'll go around our loop
again. So every time there's a START_TAG
event, and the tag is entry, then we get
ready to store the data for a new
application. Now if the event type is
TEXT, as you can see here on line 39, then
that's the PullParser telling us the
date's available. So in that case, we're
storing the data in the String variable
textValue. Now you may think that we
could store the value in the application
object at this point, but that's actually
not how XML works. Let me switch back to
the XML in Chrome, and just scroll the
raw XML up to the top. We'll go back to
our XML, and what's actually at the top there.
Now you can see the event starting tag
here, right at the top.
So at this point, the tag name would be
entry. Now as the PullParser
carries on parsing, it'll get to the
updated tag - the next line - and then
there'll be another START_TAG
event. so the tag name would now be
updated. So next there'll be a text event,
and we have that date available if you
want it - that's the date that's between
the updated starting tag and the updated
ending tag. So then it'll hit the end tag
for updated, the start tag for ID, and
then we get the URL in the next TEXT
event. So as it works its way through the
entry, the text it keeps finding changes
all the time. Now the only way that
we can be sure that the text that's
available is for any particular tag, is
to wait until there's an END_TAG event,
and store the data at that point. So
looking at the first name entry in our
event tag here, which is this one down
here. When the end tag is reached we know
that we can use the text value and
that'll be the value for the name tag. So
going back to the code. That's what the
code does - it stores the text whenever
new text is available, and that's here on
line 39, but doesn't actually do anything
with it until an END_TAG event happens -
and that's the code here that we're
testing on line 41. When we do get an END_TAG
event, we're checking to make sure the
PullParser is still inside an entry tag,
so we're checking if inEntry is set to
true. And of course, that's inEntry that we
set earlier. If it is, we can test the tag
name and assign the variable to
the correct field of the currentRecord
object. And that's what this code is
doing here - we're checking to see whether
name, artist, release date, summary or image
has been found in the XML, and we're
setting the appropriate value from our
feed entry object. And that's current
Record which we're creating each time
we're finding a new ending tag
for entry, and that's
this currentRecord. Now it's very
important to get the case right for
these tag names. remember that we convert
the names to lowercase, and we're doing
that here on line 29 - xpp.name dot
toLowerCase. So we have to use the
lowercase tag names in our when block
down here, lines 51 through 55 and also -
well basically, any part of this when
block that reference's a tag name
has to be in lowercase. So releaseDate
may cause problems, and you can see I've
made a typo here because I put release
Date with a capital D, but we have to be
consistent here and use lowercase, again,
because we've specified and converted
our tags to lowercase. So I've changed
that correctly back to what it was,
releasedate, or what it should be rather,
which is releasedate all lowercase.
Alright, so back to our conditions, when
we get an END_TAG event. The first one
checks if the tag name is entry - that's
this code here on line 45. In which case,
we've reached the end of all our data
for our currentRecord. So that means
that we can add currentRecord to the
list of applications, then set inEntry
to false, because this is the end tag for
entry. And we finish by creating a new
FeedEntry object, ready for the next
entry details, if indeed there is another
entry. Otherwise, we're checking the tag
name - the code, lines 51 through 55 - to
see if it matches any of the fields
we're interested in. If it does we set
the corresponding field of current
Record to the value that's stored in
textValue. And that's the main loop - the
only other thing I've done is added a
couple of logging lines, so that we can
see what's happening when the program
runs. Alright, so that's the main loop. Alright,
there's one more thing I want to do here,
temporarily, and that's to loop through
the application list, once all the
XML's been processed, and just print
out the values of the fields so that we
can be sure that it's worked okay. So
let's go ahead and add that code, and
that's going to be down here before the
return. So I'm going to do that, well
actually, I'm going to do it here after the
eventType xpp.next, after that
closing code block. Down here, we're going
to write the
code; for parenthesis app, app in
applications, parenthesis code block.
We're going to do Log.d parentheses, and I'm
just going to add some stars here -
some asterisks - then a Log.d TAG comma
app.toString. And I'll fix this up
as well -
TAG comma, like so. So note that I've put
that code outside of the while loop, so
as long as there's no exceptions thrown, we
should see the details for all the
applications in the logcat. And because
we overrode the toString method for
the FeedEntry class, we'll get more
useful information than we would
have got with the default function,
including the values of some of the
fields. Okay, so we're almost ready to run
the app and see if the XML is parsed
correctly. All we would have to do is
call this parse method.
So back in MainActivity, I'm going to
open that up, and the place to do
the parsing is in the onPost
Execute method, and that of course, is for
our DownloadData class - onPost
Execute. Now we don't need to log the XML
anymore because that bit's working
fine. Now we're also logging the XML
at the start of our parse function, so
there's no need to log it twice. So I'm
actually going to comment the logging
line out, in the onPostExecute function.
Then we're going to add the code to
create our parser. I'm going to type val
parseApplications equals Parse
Applications parentheses - we're creating the
object. Then we're going to do parse
Applications.parse parentheses result,
sorry results. The other thing I want to
do, is change the argument here for
onPostResult, onPostExecute, which is
result String question mark. Let's
remove the question mark,
and that fixes up that error as well. So
in the next video, we're gonna run the
application and see if it works. So I'll see
you in the next video.