Now in the previous video, we improved the
appearance of our app by creating a
custom adapter, and you can see the new
display of the app now. Now this lets us
use our own layout, so that we can
display different widgets in the
ListView,
rather than having to display all the
data in the single TextView widget that
the basic ArrayAdapter allows. Now this
gives us far more control over what
appears in each line in the ListView, and
obviously, that culminated in the display
that you can see on the screen there now.
But the actual code for our adapter
isn't very efficient, though. So we come
back and have a look, or go back to the
code - FeedAdapter - and have a look at
this getView function. It inflates a new
view every time it's called, and that's
this code here on line 29. Now that means
that if we used it to display a thousand
items, it would create one thousand views -
which is costly in terms of both time
and memory. Also, the findViewById
function is very slow because it has to
scan the layout from the start, each time
it's called, checking to see if each
widget is the one we want. And it gets
worse than that. If you start scrolling
up and down those thousand items, it'll
create a new view every time a new one
comes onto the screen. Now I can
demonstrate that, but I should mention
that what I'm about to do may not work
when you come to watch this video, and
that's because I'm going to abuse the
Apple feed. Now Apple provide a Top 10
and a Top 25 version of each feed, but we
can request the top 200 - at least, I can
at the moment. There's no guarantee that
this will continue to work in the future.
But even if it doesn't, you'll see the basic
principle with just a Top 25 - it just
won't be quite as dramatic. So we're
going to start, and make sure you cleared
your logcat. So in my case, I haven't got
it on but I'll click it there, and
I'm just gonna clear that, even though
it does usually get cleared each time we
start the app. And what we're going to do
is, we're going to stop running the app
on the device - I'm just going to click on
Stop. And by the way, you can use the menu
to stop as well, down here, but normally I
just click on this, as you can see me
doing, clicking on the stop button under
the toolbar. Now what I'm going to do is
edit the URL and MainActivity to show
the top 200 entries, and we can do that by
changing this limit.
At the moment, it's set to 25. Let's
change that to 200, and as I said, if you
get an error when you come to try this,
change the limit back to 25. The
demonstration will still work - it just
won't be quite as dramatic. Alright, the
other thing I'm going to do is make
another quick change to the adapter. Now
this isn't necessary, but it's gonna take
me a long time to scroll through the
list if I leave the summary in, because
it occupies a lot of the screen. So what
we're going to do is comment out the
code, or the line rather, that puts the
summary text into the text view. So
that's this one here; tvSummary.text
equals currentApp.summary - I'm gonna
comment that out. So let's go ahead and
run the app, and them I'm gonna come over here
to the a Android Profiler tab at the
bottom of the screen. And there's also a
button on the toolbar towards the
right-hand side, as well, if you want to
do it that way. And I'm just going to put that
emulator on the screen.
Now this is very important if you're
running on Windows. You may see a Windows
Security Alert dialogue popping up when
you first launch the Profiler. If you do,
make sure you tick the box that allows
access on private networks. Whether you
untick the other box to allow access
on public networks, is down to your
attitude to security. I strongly advise
you to untick it. What's important,
because things won't work otherwise, is
to definitely tick the Private networks
box. Once you've ticked the box, click the
Allow access button - so that's for
Windows. Now this Profiler let's you
investigate things like memory usage on
your device or emulator, so let's
actually take a look at the
memory usage.
Now the profiler's showing a real-time
view of the CPU usage, Memory and Network
on the device.
Now we're only interested in the memory
at the moment, but it's worth playing
with this Profiler and checking out how
your finished apps behave. If you get
excessive CPU or Network accesses, or the
memory starts getting eaten up when your
app's running, then you should really
investigate the cause. Now you can
drill down into each of these by just
clicking on them. If we move the mouse
down to memory, and click, you can see
that we've got a more detailed version
of memory usage. I'm just going to make
the profile a little bit larger on the
screen, so we can see what's going on. Now
usage is fairly level at the moment, and
that's because we're not doing anything.
Now before we start, I suggest you click
on the trash can icon in the Profilers
tool bar, over here. That forces a garbage
collection so that any unused memory can
be reclaimed. That way, we really know
that we're looking at changes that our
app causes. I'm going to do that now. Now
the graph shows a trash can in the
timeline - you can see that over here now -
and the memory dropped down a little bit as
a result. So we'll just click it again, and
you can see how the memory goes there
when I do that. One more time - you can
see that it's fairly stable now when
I'm clicking it. So we've got a fairly
stable amount of memory. Now in my
particular case,
I've got total memory usage at the
moment, at the top there showing as 27
megabytes. But obviously, the numbers will
vary, depending on your operating system
and what else is running, if, on your
emulator etc. Now, when we clicked the trash
can icon while testing on windows, we
didn't get those little icons in the
timeline, that you saw on my Mac. Garbage
collection still kicked in though, so
don't worry if you don't see little
icons. Alright, so now that we've got that
going, it's time to switch to the
emulator and start scrolling. So I'm
going to go back to the emulator, and I'm
going to start scrolling now.
And depending on how fast I scroll, I
can get different values. We can see
that I'm pretty easily getting up to 48
47 48 megabytes.
I'm scrolling back up again now - over 50
now, as you can see. And that will depend
on whether you're running on Windows, Mac
or Linux, as a general rule, and also what
else you've got running on the emulator.
But you can see that, basically, the
memory went up significantly, and what it
was running, before doing it. So while I'm
scrolling through this list, an automatic
garbage collection is actually kicking
in, and reducing the total memory
allocation. But we're still getting quite
high numbers - you can see there, like
over 50 megabytes is in use - and also
keep in mind that our views are really
quite simple as well. We're not
displaying graphics or anything fancy -
literally, just three TextView widgets.
Now garbage collection is also a costly
exercise, so scrolling sometimes pauses
while that's going on. To the user, the
app seems to freeze for half a second -
that can be a little bit annoying. And you
can see, there's a little bit of a - it's not
really that prominent on mine at the
moment, but if I scroll - you can see there's a
bit of jerkiness that actually happens
there. And that's the garbage collection
I clicked, kicking in - you can see the
icon there that has appeared on the
screen.
There's a big pause there, and you can
see the garbage collector icons
appearing in the right-hand corner there.
Alright, so the point is that it can be
a very costly exercise, and you know, it's
really important to be looking after the
amount of memory that your app's actually
using. So make a general note of whatever
figures you've got, when you've done this
first bit of testing. When we started
using the app, I think it was round about
26 or 27 megabytes and then rose, we
easily got it to appear over 50
megabytes, and at the moment, it's still
on 47.
So what we're going to do next, we're
going to improve the efficiency of our
adapter, and then run this test again.
So what I'm going to do is close down the
profiler, and then looking at our code - this
line of code here, on line 29. So this
line is a problem, where we inflate a new
view every time the getView method's
called. Now there's actually no need to do
that, because the ListView provides us
with a view to re-use, when it can. So
that's what, for this getView
function, that's what this convert
View parameter's for. If the ListView
has a view that it can re-use, it passes a
reference to it in convertView.
Now, until a view is scrolled off
the screen, there won't be a view to
re-use, so we have to check if convert
View is null and only create a new view
if it is null. So I'm going to alter the
getView function so that it uses the
convertView argument, and only creates
a new view if convertView is null. Now as
convertView's a val argument, we need our
own view object to store the reference
in. So let's go ahead and do that. Alright,
so what we're going to do is put val
view, and here we're going to put : view. Then
on the next line, we'll just press
ENTER there and leave the equals there.
And now what we can do, is check to see
if convertView's null and re-use it if it
isn't. So instead of just putting the
code as we had it, we're gonna come back
here and put, over here, we're gonna put if
parentheses convertView
is equal to null, code block, and then we're
going to put view equals. And then we're
going to grab this code here; else.
What we're going to do is, we're gonna
put view equals convertView. So
basically, now we're re-using the
view given it back to the adapter by
the ListView, and only creating a new
view if the ListView didn't give us one
to re-use. Now ignore this sub warning
over here in the right hand side, about
the assignment can be lifted out of the
if. It's correct - we could - but Android
Studio doesn't know what we're going to
do next and then we wouldn't be able to
treat the if as an expression. Now what
I'm going to do is add some logging, so
that we can tell when a new view's being
created, or when we we're re-using one. So
let's go ahead and do that as well. So in
the test for null, we'll actually put a
log entry in there. So Log.d TAG, and in
double quotes, we're going to put get
View called with null convertView, and
then in the else we're going to do the
same - put a log entry in there. This time,
getView provided a convertView.
Okay, so let's actually now we've made
those changes, run the app again, and see
what effect this has had on the memory.
So I'm going to, firstly, open the log
cat - I'm going to clear that - and I'm
going to run it. I'll stop it then run
it again,
and that was to make sure that the
memory wasn't being held, that it was
using previously. Open the Android
Profiler, click on memory for more detail,
and you can see we've still got a high
amount, but it's obviously nowhere near the
50 megabytes. And if I click on the trash can
icon a few times,
you can see it's getting down to 28 now.
I'm just going to do that every few
seconds until we've got a fairly stable
amount of memory in use, and we can see,
we're round about the amount that we were
using previously. And clicking on the
garbage collector is not causing, or
not having any impact on the amount of
memory, so that's good now. So now if we
run, or we move over to our emulator,
and now let's actually start doing the
same thing again. I'm gonna start
scrolling, up and down. Notice the memory
this time, when I'm doing that. It seems
to be easier to scroll, as well - it's
quicker to scroll. But the memory, you can
see that it's really not going much, if at
all, above 31 megabytes, whereas before, we
easily got to 50.
As you can see, it's far more consistent
than what it was. So that's definitely an
improvement - around about 31 megabytes -
just by making a simple change to our
code. Now with more complex layouts, keep
in mind that the numbers will get a lot
larger. Now that's a much more efficient
implementation of the getView method. So
what we'll do is, we'll finish the video
here, and in the next one, we'll actually
improve it even further by employing
something called the ViewHolder pattern.
So I'll see you in the next video.