Alright, so the changes we need to make
to the code are very simple. so you want
to open up MainActivity.kt,
which I've got opened up here now, and
let's make those changes. Now we've seen
how to add a synthetic import to let us
refer to the layout's widgets directly,
but when we did it before, we typed the
import in manually. So this time, we're
just going to use the widget and let
Android Studio take care of the import
for us. So we're going to be adding the
code to the onPostExecute of our
DownloadData class, and you can see, I've got that
on the screen there. And this is where
things get a little bit tricky. So I'm
going to start first by adding, or
creating rather, the ArrayAdapter. So I'm
going to do that under this last line
here, and I'm going to type val array
Adapter equals ArrayAdapter. Then we
need the diamond operator,
FeedEntry, and then outside, parentheses.
Now when we try to create the Array
Adapter, Android Studio's suggesting that
we have to provide a Context. Now a Context
describes the application environment, or
in the case of an Activity, the
Activity's environment. Now it knows
about things like the screen that the
Activity is using, and all sorts of other
configuration information. now the usual
things to provide, when you have to use a
Context inside an Activity, is a
reference to the Activity instance. Now
that would normally be this - the current
Activity instance, but our code's not
running in MainActivity - it's running in
this nested DownloadData class. Now if
we'd left downloadData as an inner class,
we wouldn't have a problem. But if you
recall, Android Studio persuaded us to
make it a companion object - and that's
this one here, the reference on
line 40 - to avoid memory leaks. So as a
result, we no longer have access to our
containing MainActivity class. But okay,
that's not the end of the world. What we
can do, is we can pass in a reference to
the MainActivity instance, when we
create the DownloadData object. So let's
see if that'll work. So we've got this
reference here on line 41. So at the
moment, we've got Async, as you can see
there. We've got private class Download
Data Async,
then diamond bracket, diamond operator,
String, Void, String. We can try changing
that, so let's go ahead and put
parentheses after the DownloadData, and
in there we'll put Context : Context
with a capital C, comma. Then ListView :
ListView with a capital L and a
capital V. Now if Android studio didn't
add those imports automatically, like it
did for me, just use Alt-Enter to get
the imports added. But in my case,
because I've configured Android
Studio that way, it's automatically added
the imports. Now we're going to use the Context
and ListView in our class functions, so
we need to provide backing fields for
them both. So we're going to do that down
below the tag line here, on line 44. And
by the way, we'll talk about this towards
the end of the video - this little pop-up
in the corner - because you'll probably
get that from time to time. So we're
going to type, on line 46, var prop
Context : Context, with a capital C, equals
context. Then var,and I'll call this one prop
ListView : space ListView
equals little listView - you fix the typo. Now I
don't recommend this naming convention,
by the way. I've just made it up - but I
want to be clear about what we're
referring to,
so I've prefixed both these backing
properties with the word prop. But please
don't do this.
I've done it so there's no confusion
between the properties and the
parameters passed into the class to
initialize them. Alright, at this
point though, we've actually got some
warnings - we've got some warnings
over here - and we've also got an error.
And we've still got an error, both there,
which we looked at previously,
which we were addressing, and we've also
got another error, up here, relating now
to line 37, and the call to the
DownloadData function. So the first one
on line 37 - well that's just because we
changed the declaration of DownloadData
but we haven't passed anything to it.
Let's go ahead and change that first, so I'll
up to here on line 37, and what we'll do is,
we'll add this
as the first argument and a comma
space. Then XML ListView as the second
argument, and that should fix that error up.
And you saw that when I
referred to XML ListView, Android Studio
adds the synthetic import for us, and
that lets us refer to any of the IDs in
the layout, without having to keep
calling findViewById, which obviously, is
good. Alright, so that's fixed one of
the errors but I've still got this
option here, this error here - Array
Adapter - which we need to address. We've
also got these warnings as well. Now
remember that the only reason we changed
Downloaddata from an inner class to a
companion object, was to avoid leaks. And
if we have a look at these warnings, the
field leaks a context object. Well we can
see the first one; propContext is
never used, but the second warning; This
field leaks a context object. Now if your
Asynctask doesn't have to update the
User interface, then by all means use one.
If you do have to update the UI - as we do
here - then I'd suggest using an alternative
approach, and we'll see that one in a
little while. But first, though, let's see if we
get this working. So what we can do, is we
can avoid these leaks by using a
delegate, which will result in only weak
references to the context being held. So
we can come back up here to our line
again, there, propcontext colon context.
then we can put, after the word Context,
by delegates.notNull, like so, with
parentheses. And we can do the same on
the next line. So there, propListView :
ListView equals, and we'll change that to
Delegates.notNull
in parentheses. And of course, I need the
word by, as well - by Delegates - to fix that,
and get rid of the equals. So, we've Context by
Delegates.notNull, parentheses, and
ListView by Delegates.notNull.
parentheses. So that should fix the
warnings. We're now only getting the
warnings now about the fact that they're
never used, and which is correct at the
moment. But we've also got this other
error to fix down here, as well. But firstly,
what we need to do now, is give our
properties, given values. So we need to add
an initialization block to assign the
arguments to our properties. We can go
ahead and do that, just under there.
We can type init and add a code block,
and within there, we can type prop
Context equals context. Then on the next
line, we can type propListView equals
listView.
Okay, so that's now initialized them as
well, and you can see that the warning's
now disappeared because they are actually
being used and have been initialized
correctly. So that's cleared the warnings
and now we can complete the creation of
our ArrayAdapter, because obviously
that's still showing an error here. So we
can change that to Val arrayAdapter
equals - and we'll change that to adapter
with an e - and it equals ArrayAdapter,
then it's FeedEntry, and within the
parentheses, now, we want to update this.
I'm going to type propContext comma R
dot layout.list_item
comma space, and it's going to be parseAppilcations
dot Applications, and obviously, the right
parenthesis as well. And you can see now,
that the error has disappeared. We have
got a warning here, just that the fact
that the arrayAdapter's not used but
that's okay for the moment. So, this
definition works but it's a bit messy.
It's also not very readable and not
immediately obvious what exactly will
happen, if our Activity's destroyed while
the AsyncTask's still running. So I'm
going to deal with that shortly. Now our
data, if you recall, is an ArrayList which
we can get from the ParseApplications
class by using its applications property.
So we can see it if we go back to our
ParseApplications and look at our
ArrayList.
The ArrayList that contains, over here,
the
list of applications we parsed out of
the XML data. So all that really remains
to do, is connect the data to the
ListView. Let's go back to our Main
Activity again, then on the line
following that val ArrayAdapter, we're
going to type propListView.adapter
equals arrayadapter. And you can see all
the warnings and errors have disappeared
now. So we create a new Arrayadapter
object. Now that needs three arguments -
this is this code here on line 62, I'm
talking about. The first is the Context. Now
I'm going to talk about Context a bit
later, because it's probably a good idea
to see this working first. For now, though,
we're just gonna pass in this instance
of MainActivity - this propContext. Now
the second parameter is the resource,
containing the TextView that the Array
Adapter will use to put the data into.
Now if you recall, we created that in the
layout file list_item dot
xml, and so therefore, I'm passing
R.layout.list_item for
the resource argument, to link those two
together. Now the third thing it needs is
the list of objects to display, and
over here, we're using the applications
property of our parseApplications
instance, to provide the ArrayList of
FeedEntry objects. So the only other
thing to do, is use the ListView's set
Adapter method, to tell it the adapter it
should use to get its data - and that's all
there is to it.
You add a ListView widget to your layout,
you create a TextView resource, create an
instance of an Adapter, and then call the
setAdaptor function to link the
ListView to the Adapter. You can see
we're doing it here, by just setting the
property directly in Kotlin to achieve
that. And what we should be able to find
now is, if we run this application, we
should find that the Top 10 Free
Applications will be displayed in a
scrollable list. Alright, just before I start though,
I just wanted to briefly open up our
emulators, and to let you know that I'm
now using the Nexus 5X API 26, and I'm
using the Google Play version of that.
Now there's a few reasons for that.
Firstly, you noticed in a previous video, if
you
recall, there were lots of errors
relating to my emulator. So by switching
to a Nexus 5X, which is more
appropriate anyway, because a Nexus 4
doesn't run the latest version of
Android anyway - so even in an emulator, it
makes sense to use a new version. But the
Nexus 5x is also good because it
supports Google Play API's, and that's
really useful for testing applications
that are using Google Play. So I suggest
you switch to that emulator, and just to
give you a bit of a lowdown on that, the
other thing I'd recommend - we'll just go
back into Tools briefly, then go into
Android and go into to SDK manager, the other
thing I didn't make sure that I had set,
and click on Show Package Details over
here. Then notice that under Android 8
Oreo, I've got the Google Play Intel x86
Atom System Image. So you want to make
sure you're using that one and not the
API - the Google APIs - because the Google
Play one gives you that extra option to
run the Google Play apps, or apps that
support or use Google Play
functionality, and that's very useful. So,
the other thing to keep in mind - I'm
going to cancel out of that now, though,
going back into the emulators - there's
only a few devices that can actually run
this Google Play version of an emulator.
Nexus 5x is one, and I think Nexus 5 is
another one. Most likely, when the new
pixel devices get released by Android,
you'll probably find they'll run it as
well. But if you're trying to set this
Google Play emulator,
this particular version, on another
device, more than likely it won't work in
an emulator,so just keep that in mind. So
in my case, what I've done is I'm using
the Nexus 5x from now on, and I'll use
that for all future emulator tasks in
this course, and I've actually got that
running now, as you can see there. Al
right, so let's now try running this and
see what happens. OK, running on the Nexus
5x - let's have a look at it.
Okay, you can see there's our applications -
our 10 applications - appearing in the
list, and you can notice that I can
scroll them up and down now. So we're in
the scrollable ListView and things are
working nicely. Now if I go back to our
code - go back to Main Activity. If I change
the limit from 10 to 25 in the URL -
that's this one here on line 40. So come
over here and change that to 25, and run
our app again, we'll actually see the 25
apps instead of the top 10. So you can see
the list, now, is actually longer than
what the top 10 was before. So we still
have the ones that we had before but you
can see that I'm scrolling down further
now, and getting access to other apps as
well.
So that's clearly more than 10 apps. So the
ListView is able to support a variable
number of items to be shown. So you don't
have to change any code to make it
display more records, if you've got more
records to display. Alright, so let's
finish the video here, but before I do
that, if you do get these updates, and
they will come through from time to time,
I suggest you actually go ahead and
install them. To do that, you can just
click on Install, and depending on when
you're watching this, Android Studio is
getting smarter and smarter with Kotlin
code and giving the ability to do this
automatically. So click on Install and it
should download and install that for us,
and that's just enhancements to Kotlin
and to the plugin, and to the language.
We'll then need to restart to activate
the changes,
and as you can see, it's indexing, which
it'll do for the first time with a
new version. But all our code is there, and
if you do get a message like this,
then click on this and click on Update
Runtime. And again, depending on where we
are and what the status is with Android
Studio, this could be an automatic thing.
But you can see that Automatic library
version update for Gradle projects is
currently unsupported, and that's
relating to Kotlin. You'd find if this was
Java, that would actually be working
automatically. So you may not get this by
the time you get around to seeing this,
but if this does come up, close it down,
click on the event log. We can see here
that it says your version of Kotlin
runtime is Kotlin STD, but
basically, the important part is these
numbers here; 1 1 4 3, or plugin version 1
1 5 0. So, you just take these numbers,
obviously, 1.1.50 is greater than
1.1.4 - 3, so I'm gonna copy the 1 1
5 0. I'm going to close down the event
log, then I'm gonna open my Gradle scripts.
I'm gonna click on this first
build.gradle. You can see where it's got
ext.kotlin_version equals 1.1 point
4 - 3. I'm gonna change that
to the newer number, and for some reason
that didn't copy. I'll just try it again -
copy. If
it doesn't copy I'll just type it in.
We'll close off the event log again, back
into here and paste it. Let's go. That's
better this time, and click on Sync Now,
and that should actually now update our
project to be using the latest version
of Kotlin. And you can see down the bottom,
it's working away and downloading what
it needs to make that happen. And the
downloads are generally a once-off
process, so you can find
that it takes a while the first time but
then once that's done, it's downloaded
and these relevant files are on your
computer, and subsequent to compilation
and opening projects etc will be a lot
faster.
Alright, so you can see it's finally
finished then, and we can just test that.
We can actually close down the project
and open it again, and this time we shouldn't
get any warnings. You can see it's now happy,
and I can close down the build Gradle
script now because we're now
running the latest version. Alright, so
let's finish the video here now. So in the
next video, we'll start having a
look at the interface because, obviously,
it wasn't terribly pretty - if we go back
and have a quick look at it. Actually,
we'll just run it again.
So as you can see, it's not terribly
pretty but we'll have a look at seeing
what we can do, to make that a little bit
nicer in the next video.