Alright, so we've now got some data
downloading, so it's time to do
something with it.
So let's start by having another look at
the XML in the browser. Now I'm going to
use Chrome, because we can view the XML
in a much clearer way than some other
browsers. Chrome's inability to render
the RSS feed is great when you want to
view the feeds XML. So I'm going to open
a browser, and I'm going to go to
apple.com, and forward
slash rss, and I'm going to have a look at
the Top 10 Free Apps which was the RSS
we've been working on. And there's the
XML, as you can see there. So we can close
down or collapse any tags we're not
interested in, by clicking on these
little triangles here. And that can help
us to remove some of the clutter, and
give us a better feel for the data. So
I'm going to collapse this first entry
tag here and we can see that it's
followed by another, and if I keep
collapsing them, you probably won't be
surprised to see that there's 10 of them
in all. So let's go ahead and do that, and
there's the 10 all collapsed. So these
entry tags contain the information on
each of the applications that are in the
Top 10 Free Apps feed. Now all this stuff
at the top is the information about the
feed itself, so there's a title for the
iTunes Store Top Free Apps, and the
author's name in iTunes Store, down here.
And we can see when the feed was last
updated, but we're not going to be using
any of that in our app - we're going to be
concentrating on the information in the
actual entry tags. So I'm going to expand
one of these entry tags again, and we can
see the individual fields that we're
going to be using. Now the information
we're interested in from the feed is the
name, the artist, release date and
summary. Now the entries also contain
links to an image for the app, and we're
going to add a field to store that as
well. Now we won't be displaying the
image in this app, but having the URL
will make it easier if we want to add
the image once we've seen how to
do that. So what we're going to do is
parse out the individual fields from the
XML, so what I'm going to do is start by
creating a basic class that we can use
to hold the information. Now this class
is really no more than a way to store
the individual entries that we extract
from the XML. Now I'm not saying you
should do this and I'm not saying you
shouldn't, but I'm going to put our Feed
Entry class in the same file as Main
Activity. So I'm doing this again just to
show you that I can. Kotlin doesn't have
the same restriction as Java, so there's
no requirement that a class must be
in a file with the same name. And because
this is such a simple class, it's a good
way to demonstrate that. But one thing I
would suggest, is if you put a very small
class in the same file as a major class -
and MainActivity's pretty major,
it's where the app starts - then put it at
the top. If you put it at the end of the
file, it's very easy for people to not
notice it's there. And I would also
suggest that if a class takes up most of
the screen, it really should go in
its own file. But as far as Kotlin is
concerned, it makes no difference either
way, so we're just considering people who
may come along afterwards, to read and
maintain our code. And remember that that
person could well be you,
months down the road. Of course, if you
work for a company whose style guide
prohibits putting more than one class in
each file, then you'd want to obviously
follow their guidelines. Alright, so
what I'm going to do is go back to
Android Studio,
and making sure that I've got Main
Activity.kt opened, and I'm
going to come up here and add the class
entry, starting on line 9. So I'm gonna
start with class FeedEntry, and we add
the opening and closing curly braces. And
we need to add some fields, so it's going
to be var name colon string equals, and an
empty string, two double quotes, var
artist colon string equals two empty, or
two double quotes, var releaseDate.
So releaseDate string equals two double
quotes, var summary colon, you guessed it,
string equals, in two double quotes, and
finally, the imageURL, that's also gonna
be a var, imageURL - that's also a string -
and we're initializing it to an empty
value. So as I said, it's a very simple
class, and it just holds properties for
the data that we're going to extract
from the RSS feed. Now each time we
create a new instance of FeedEntry,
it'll store the details from one of
those entry tags that we just looked at
in the browser. Now when you create a
class, it's often a good idea to create a
toString method that can be used to
print out a representation of a class
instance.
Now here it'd be useful to display some
of the fields. Now we can actually get
Android Studio to generate the basic
stub for us. So to do that, we want to
make sure that the cursor is at the end
of the class but before the closing
brace - I'm going to put it there - and then
we use Ctrl-o to generate the code. We
want to come down here and choose to
String, to get Android Studio to create a
basic toString method for us. So I'm
just going to press ENTER there, and you
can see it's created that function for
us. Now part of the reason for including
this, is to show you a neat feature of
Kotlin when it comes to dealing with
strings. We've already used template
expressions, also known as string
interpolation, and we're going to use
some of those here. But Kotlin also
provides an easy way to create
multi-line strings. Now we do that by
using triple quotes. So what I'm going to
do first is delete the super call in our
toString function, and that will just
return the default details in our class,
and we're going to add some extra code
instead. So I'm going to type return,
three double quotes, enter, name equals
dollar name, enter, artist equals dollar
artist, enter, releaseDate
equals dollar releaseDate and image
URL equals dollar imageURL. Then we're
going to finish that with three triple
quotes, like so. So the neat thing about
that, using triple quotes in this way, is
that we're going to get each property
printed out on a new line. Now because
we've formatted the code with spaces to
line everything up, we also get a load of
spaces at the start of each line. Now
that's not a huge problem but it's
easily fixed - we just tell Kotlin to trim
off the indentation. So to do that, at the
end of the closing triple quotes, we type
dot trim indent - we're adding a call to
the trimIndent function. Now that will
only work if you put name on a new
line, like I've done here. If it was
on the line above, it would have no
indentation and trimIndent uses the
line with the smallest indent, to work
out how many spaces to delete. Now we're
leaving the user interface for this app
until last, which means we need
some way to tell that everything's
working okay. So in case you hadn't guessed,
we're going to use this toString
function, to display our entries in the
log. Now every object has a toString
method that's used to provide some sort
of textual representation of the object's
instances. Now by default, it just shows
the name of the class and the instances
hashcode, which is just a number that
uniquely identifies each instance. But by
overriding the toString method, we can
get a more useful representation of each
object, so that our log will make a lot
more sense. Alright, so that's the Feed
Entry class created. Every time we get a
new entry in the data, we're going to
create a new FeedEntry object, and set
the fields to the values that we find in
the XML data. We now need to create the
code to parse the XML - in other words, to
find the various fields that we're
interested in and extract the values.
We're then going to store those values,
as I mentioned, in the individual
FeedEntry objects. Now the good news is
that we don't have to write loads of
code
to go through that stream of XML, and
checking for the less than and greater
then symbols to work out where the tags
are, then working out the values and so on.
Now we could do all that if we really
wanted to, but parsing XML is a very
common thing for an app to do, so there
are libraries included in Java that take
care of all of that for us. Now there are
some Kotlin libraries, for parsing XML,
starting to appear, but I don't want to
add external libraries to our projects
just yet.
And also, the Java libraries have been
tried and tested for many years, so we
know that they work well. Alright, so
the library will deal with working out
where the tags are, and which bits of the
XML are the actual values, and so on. We
can then use the library to read the
values for the tags that we want. So what
we're going to do is create another
class to handle the parsing. Now I'm
going to put this one in its own file,
and I'm going to do that by right-clicking
the package up here - academy.learn
programming.top10downloader -
right-click and click on New, and select
Kotlin class, Kotlin File/Class.
We're going to call this one Parse
Applications, but don't press OK just yet,
because notice that the kind of thing
that we're creating here is a file. Now
that's fine - everything will still work
if you leave it at that, but you have to
type in the class declaration. So instead,
what we're going to do is change that to
class first, and Android Studio will
then do so of the typing for us. Now the
icon's also a bit different for Kotlin
files and classes. That may be useful to
help you identify the types of file in
the project pane. Now if the file only
contains a single class, it has that Ck
icon. If you then add another class or
some code outside the class, it changes -
like the icon showing for MainActivity.
So I'm going to click OK now and we'll
get our new class created. Ok, so you can
see Android Studio has created that
class for us. Now it's always useful to
write log entries to see what's going on,
so I'm going to start by adding our
usual log tag.
Now we're going to build up a list of
FeedEntry objects. These will be created
as we pass each of the entry tags in the
XML, and will be stored in an ArrayList.
So I'm going to call this one
applications. So we do val applications
is equal to ArrayList, then diamond
operator, FeedEntry. Then outside the
diamond operator, we're going to have
parentheses. Alright, so that's the basic
setup done. What we need now is the
function that'll parse the XML data and
create the list of applications from it.
Now I'm going to call this function parse,
because that's what it's going to do.
Let's go ahead and create that. So it's
going to be fun parse, and in parentheses,
xmlData colon String and then colon
boolean. Then left and right curly braces
to define the function. And the actual
code, we're going to start by putting a
Log.d parentheses TAG comma. Then it's
going to be parse called with dollar
sign xmlData. We're going to put var
status equals true on the next line.
Next line, var inEntry equals false.
Next line, var textValue equals, an
empty string - two double quotes. So this
function takes a single argument which
will be the string to parse. Now I've
made this function return a boolean
value. If there are any problems, it will
return false, to indicate that the data
couldn't be passed for whatever reason.
The variable status is initialized to
true, and will be set to false if an
exception is thrown.
Now the code will also have to make sure
that we're processing the data inside an
entry tag. Now that's important because -
and if I switch back to the XML in Chrome
here - you can see that a name tag can
appear outside of the entry
tags, as this is the case up here. But it also
appears in here as well. We've got the
name here as well. So basically, you can
appear within the author tag as well as
inside an entry. Now we don't want to go
adding that name - the first one outside
of the entry tag - into a FeedEntry
object. So to deal with that, we'll keep
track of whether we're looking at the
tags inside an entry or not. And
getting back to Android Studio - that's
using this variable in entry. Now text
Value - that's used to store the value of
a current tag, so that we can assign it
to the appropriate field of our Feed
Entry object. And in terms of processing,
we're going to wrap up that processing
inside a try block. So let's go ahead
and do that - try. We're going to do a
catch parentheses e colon exception, and
we're going to put e.print
StackTrace, if we do get an exception, and
set status equal to false, as I mentioned.
And then outside that we're going to
return status. Now I haven't specified any
particular exception here, so if anything
goes wrong, any type of exception will be
caught. If that happens, the status will
be set to false, and we're printing out a
stack trace to help us diagnose what
went wrong. Now we're gonna return the
status, which will be false if there was
an error, otherwise it'll be unchanged
from its initial value of true. Alright,
so the next few lines of code we're
going to add, set up the xml classes that
are part of Java.
So let's go ahead and do that, and that's
going to be within the try block. I'm
gonna type val
factory equals xmlPullParserFactory -
I'm selecting that from the drop down -
dot newInstance. On the next line,
factory.isNameSpaceAware - we're
sitting that equal to true - and we're
going to do the next line, val xpp
equals factory.newPullParser. The
line after that, we're going to do xpp
dot setInput.
I'm gonna set that to xmlData.reader.
Then we're going to do var eventType
equals xpp.eventType, var current
Record is equal to FeedEntry, and then
we're going to put while parentheses
eventType is not equal to xmlPull
Parser.END_DOCUMENT, and
I'm gonna leave that part empty for now.
So lines 22 through 24 - they're
responsible for setting up the Java
XML parser, that's going to do all the
hard work of making sense of the XML for
us. Now the important thing is to
know how to use the parser - it's not
necessary to know how it works. Now I'm
going to explain the way it's used in
our code here, but if you actually want
to learn more about PullParsers, then
you'll find plenty of information online.
Now the PullParser site - I'll just
briefly bring that up in a browser now -
you can see there, it's available at
www.xmlpull.org. That explains about it,
and what's more, it also contains the
link to the Java API documentation
towards the bottom of the page. And the
other thing to note is, there's also
Android documentation available. We'll
briefly go and have a look at that - this
is for the xmlPullParser again - and
that gives details on all the constants
and methods available. Now you can't just
go creating instances of PullParser
objects as you need them. So instead, if
we go back to our code, the API provides
a factory that will produce a Pull
Parser object for you. Now class
factories are common in Java, and are
often used when you don't know the
actual class that's going to be used. Now
we don't really care which class will
provide the parsing functionality that
we need - all we're interested in, is that
it, in fact, can parse XML. So as long as the
object we get back recognises the
methods defined in the XMLPull API,
our code will actually work with it.
Now although you can dig a lot deeper
into how all this works, and investigate
all the various functions available, the
beauty of using the supplied Java
class is that you don't actually have to do
that, in order to get results. Once you
know how to create the objects, you can
just use them without worrying about
what they're doing behind the scenes. Now
obviously, when you get into more
advanced stuff, then you may want to
understand what's happening more, but
when you're just starting out, it's okay
to just use the built-in classes to get
the job done. So by the time we get to
line 25, we have a valid PullParser
object, so we can tell it what to parse by
giving it a StringReader, that's using
the xmlData String. Now a StringReader,
by the way, is a class that treats a
String like a stream. So think of it
as an efficient way of processing
strings, and the way that the XMLPull
Parser does things. Now you probably saw
it pop up that it wanted a Reader when I
typed the opening bracket after set
Input. So the XMLPullParser needs a
StringReader to read from, and a String
Reader needs a String to read - which is
what we've got on line 25 there. Kotlin
makes that a lot easier. It provides an
extension function that returns a String
Reader for us, already set to read from
our xmlData string. Alright, so let's
finish the video here now. In the next
video, we're going to talk a bit more
about the PullParser and also the
Reader, just to clarify, and then move on
to adding more code to our parse
function. So I'll see you in the next
video.