Alright, we've now got our app
downloading the RSS feed, but I mentioned
previously that experienced Kotlin
programmers will probably have been
horrified by some of the code that we've
created so far. What we've got is
basically Java code, but written using
Kotlin syntax. In fact, we could have
pasted in the equivalent Java code
and got Android Studio to convert it for
us, and always there'd be a bit of
tweaking needed but it would largely
work. But that isn't how the downloadXML
function would be written in Kotlin,
though, so let's have a look at how we
can tidy it up. So what I'm going to do is
start with the catch blocks. Now at the
moment, we've got four catch blocks, which
all do just about the same
thing - they log the error. Now apart from
the stack trace for the security
exception, the only difference is part of
the stream that we're logging. Now we
could put those individual pieces of
text into a variable, and have a single
logging call, but Kotlin allows
us to handle things even better than
that. So what I'm going to do is start by
commenting out all the current catch
blocks, and then what I'm going to do is
type it in a more Kotlin-like way of
dealing with them. So I'm going to come
down - actually, what I'll do is, come
down here. Then we'll do a catch, and in
parentheses, e colon space exception, a
code block, then we're gonna type val
errorMessage colon string. Next line,
when, e in parentheses and a code block.
We're gonna type is MalformedURL
Exception, then an arrow token, error
Message equals downloadXML Invalid URL,
dollar sign
left and right curly braces, e.message.
Then - and just fix up the typo there - error
Message. Next line is IOException, the
arrow token again, or
the arrow, depending what you want to
call it - it's got quite a few names out there -
errorMessage equals. This time it's going
to be downloadXML again, and IO
exception reading data colon space and
dollar sign, left and right curly braces,
e.message again. Next line is Security
Exception. We do this one slightly
different so I'll have our arrow token
again and then we're going to add a code
block. we're going to start with e dot
printStackTrace. Then on the next line,
I'm going to put errormessage is
equal to downloadXML : and this time it's a
security Exception, and what Needs
permission question mark and then we'll
put the space and a dollar sign, left
and right curly braces e.message
again. And we'll close off that code block,
and we'll end on the next line with else
and the arrow token again, errorMessage
is equal to Unknown error : dollar sign
left and right curly braces, e.message.
So now we've got a single catch block
and we can test the type of the
exception, using when. You can see that on
line 85. Now we can improve that even
further, and in fact, Android Studio is
suggesting a way we can do that. So if I
actually click on when, on line 85. Come
over here, we get a tool tip - well
actually, we can come over here and see
the tooltip; Assignment can be lifted out
of 'when'. What that means is that each of
the cases inside the when block are
assigned a string to errorMessage. Now
many things in Kotlin can be used as
either an expression or a statement. So
we can use our when block as an
expression and assign the result to error
Message. So to show you what I mean, I can
come over here now that I've actually
selected when, click on this and click on
Lift assignment out of when, and you can
see that's made that far more concise as
well. And we can even remove the
declaration on line
eighty-four. so if we click on that line,
you get this toolbar, or we can hover
over it first - Variable errorMessage is
assigned but never accessed. Just
come over here and click on the line,
and we want to click on Join declaration
and assignment. So that's a lot nicer and
even more concise than what we had it,
and I think you'd agree that looks a lot
tidier than the previous code. Now using
a block of code as an expression, as
we're doing for each of those branches
in the when, causes the last statement in
the block to be used. Now we've made sure
that the last expression in each branch
is the string that we want to display in
the log. Now that's only relevant for the
security exception, because that's the
only branch that's got more than one
statement, but that's why we had to call
printStackTrace before creating the
string. Now the same warning about the
order of the exception still holds here.
We have to list MalformedURL
Exception before IO exception, for
example, because MalformedURL
Exception is a subclass of IO
Exception. Okay, so we can also improve
the way we read from the inputStream.
Now Android Studio won't help with that,
and the Kotlin code that we'll use is
very different to what we've got here
currently.
Alright, so let's just look at the input
Stream code. So we come up here and have
a look at it. Now Android Studio won't
help with that, and the Kotlin code that
we use is very different to what we've
currently got here. What I'm going to do
is start by deleting the code that we
commented out in an earlier video - these
three lines that we replace with a
single line. Let's just get rid of those
to free up a bit of space here. Now I'm
going to comment out all the code that
we're going to replace, just so you can
compare it to the new code. So we've got
this val reader - we're going to start
on that line. I'm going to move right on
down now to, and including, the reader dot
close, and we'll comment that out, and
instead, what I'm going to do is add the
replacement code, and I'm going to add
the replaceable code below it. So the
replacement code is going to be val
stream equals connection.inputStream.
Then I'm gonna type stream dot
buffered.reader, parentheses there, dot
use, open a code block, and then I'm going
to type in the code block, reader arrow
token, or arrow. On the next line, xml
Resul.append reader.readText.
Then we've got our closing right curly
brace. Now that's definitely more concise
than the code above it and demonstrates
the different approach that functional
programming takes. So instead of
concerning ourselves with the exact
details of how to read from the stream;
using a while loop, counting the characters
received, looping until there's no more
data, and so on, we focus on what we want
to do. So the functional style let's us
specify what we want to do, which in this
case is, take our stream, buffer it, get a
reader and use it to read text and
append the results to our StringBuilder,
which is xmlResult. Now I'm going to
be using the functional programming
style a lot throughout the course,
because the code's a lot cleaner. Now
comparing that code to the code I
commented out, and it's easy to see that
there's far less scope to introduce
errors. We don't have to think about
whether we should be checking for
characters, for charsRead greater than 0,
or charsRead greater than or equal to
zero, for example. It's getting details
like that wrong that can cause subtle
bugs in our code. Now if you're not used
to functional programming, it can take
some getting used to.
Let's just take a moment to see how we
can tell what's going on here. So we're
starting off with an inputStream which
we're getting from our connection - it's
connection.inputStream. That bit's
unchanged, although, we don't really need
to store it in a separate variable. I
just did that so the change is a bit
less drastic. Now we can actually get rid
of stream and do this instead. So I'm
going to delete that first line. I'll
comment out that first line. I'm going to
replace stream with connection.input
Stream. That's even more concise, as you
can see, and to see what buffer is doing,
we can control click on it
to see the Kotlin source. Come over here
and click on it,
remembering it's command on a Mac. Now
the comments here are normally
sufficient, rather than trying to
understand the code, but here we can see
that it creates a BufferedInputStream,
wrapping this stream, which is exactly
what we did in the earlier code when we
used the BufferedReader. Now below that, by
the way, is the InputStream.reader
function, so there's no need to go back
to the code to control or command click
on reader. And it creates a reader on
this InputStream, again, just what we had
in the previous Object Oriented
Programming code, using the InputStream
Reader. So, so far everything's been
pretty much the same. Where it gets
really interesting, though, going back to
our code, is when we use this lambda to
do the reading. So if we come on down
here and we want to control click use, and
we can see that it executes the given
block - that's our lambda on this resource -
and then closes it down correctly. Now
that removes the need to call reader dot
close, and it'll deal correctly with any
exceptions that have thrown. Now the
function code itself may look a bit
complex but don't worry about that.
When using the Kotlin or Java libraries,
we're interested in what things do, not
in exactly how they work. We're learning
how to write apps, not learning how to
write the Android framework. Now the
lambda function uses the reader
parameter to read the text and append it
to xmlResult. So it's worth having a
quick look at the readText
function. So if we just close that down
and go back and ctrl-click the readText
function, or command again on a Mac, and
you can see it says it reads this reader
completely as a string. And again, that's
good -
that's exactly what we wanted it to do.
What's interesting, though, is how it does
it. It uses copyTo and the source for
copyTo appears just below. Now if we just
scroll down and have a bit of a look there,
if that looks familiar, then it should.
Now I haven't done this in a video
before but in theory it should work. So
I'm going to drag the tab for the
ReadWrite.kt file out of Android
Studio so it appears in it's own
window. And to do that, I just need to
make this window a little bit smaller, so
I'm gonna go ahead and do that. So I'm
gonna drag that out, and then I'm going
to go back and expand this again, and
we've got this other window now. So what
I'm going to do then, is I'm going to go
back to our MainActivity. I'm going to
close down the project pane to make a
bit of space. Then I'm going to bring this
back again and just make it a little bit
smaller, so that it actually fits a
little bit better, and we can compare
this code now, on the right hand side, to
the code that we've got commented out. So
we're, basically, comparing the two sets
of code. Now the variable names are
different but you can see that both bits
of code use a CharArray as a buffer, and
use a while loop to keep reading until
the number of chars read is less than
zero. So, ultimately, our functional code
is doing the same thing as our previous
code. Now one advantage of using
functional programming is that this
library code, in ReadWrite.kt, has
probably already been used in thousands
of programs. The more people that use
Kotlin, the more these libraries get
tested and any bugs get ironed out. Now
the while loop that we had earlier would
need to be tested, and if there was a
subtle bug, there's far less chance that
we'd spot it. So as well as cleaner code,
we also get the benefit of all that
extra testing that the standard
libraries are subjected to. So I think
that makes a good case for using
functional programming wherever possible,
so that's what I'm going to be doing it
throughout the course. Alright, so I'm going
to close down this window now. There's
one more change we're going to make to
our lambda. Now if you've taken Sara
Etrich's Kotlin for Java developers course,
which is a course from the learn
programming academy as well, you'll know
that we don't have to use an explicit
parameter here - we can replace reader
with it. I'm getting back to the code,
again, here on line 65. So again, for that
lambda, we don't really have to use an
explicit parameter - we can replace reader
with it. And Android Studio actually
suggests that, in fact. If I click on
reader, we'll get a suggestion over here.
I come over here and click on the
light bulb.
We can replace explicit parameter reader
with it. So I'm going to do that by
clicking on it, and I can just put that back
so it's all on the same line now - just
removing the whitespace and we can
even remove the next line. So with a
single statement like we've got now - and
I've done that because in a single
statement like we've ended up with, it's
usual to put it all on the one line which
is why I've done that. But that one line
of code replaces all the commented out
code above it. I think you'd have to agree
that's pretty impressive - so impressive
that we better run the app again to make
sure it still works. So let's just do
that - make sure that things are still
working. Looking at our logcat, and you
can see that we've still managed to
download the XML, so everything's working
fine. And just confirming that our events
are still being called; we're still
getting the response code of 200, and the
XML, and the amount received, etc. Al
right, so I want to stop this video here.
The next video is going to be a very
short one, just like the code we're going
to produce. I'm starting a new video so
that this code's available with the
resources for this one. Now there's a
reason for that, and the reason is I'm
going to delete all the code in this
method and replace it with a single line.
That's right - the 27 lines of code we've
got here can be replaced with just one
line in Kotlin. So let's work on that in
the next video.