MID-YEAR SALE: 25% Off Certificates and Diplomas! Sale ends on Friday, 3rd July 2020Claim My 25% Discount
We'll email you at these times to remind you to study
You can set up to 7 reminders per week
We'll email you at these times to remind you to study
Guy: Hi, everybody.
My name is Romain Guy.
For those of you who don't know me yet,
I am a software engineer at Google on the Android team.
I do a bunch of things.
I work primarily on the application framework,
the UI toolkit, the home screen,
and a couple of tools.
So if you have troubles with your home screen
or some widgets, it's probably my fault.
So you can insult me on the--all public forums.
And today we're going to talk about
how to improve the performance of your UI
when the stupid animation is over.
Here we go.
How many of you have had performance issues
in their Android UIs?
Raise your hands, don't be shy.
Okay, quite a bit.
So the rest of you, like, you don't try the applications
or your code is perfect?
Who never wrote an Android application so far?
That's good, I like you guys.
Because now you have phones, you can do that.
Before we start, throughout the session,
I will give you some numbers to give you
a better understanding of how the various
tips and tricks I will give you
will improve the performance of your application.
Some of those numbers
come from recent experiments I did.
Some of those numbers are pretty ancient.
Some of those numbers are, like, 18 months old,
so that's before Android 1.0.
So if I tell you that the application
was running at 30 frames per second,
it's probably a lot better now,
but at least the relative differences will be the same.
And all the numbers I will show you
were taken on T-Mobile G1,
to a prototype of the T-Mobile G1.
And again, if you have one of the newer devices,
it's probably better.
So this is our agenda.
We're gonna start with one of my favorite topics,
So how many of you have ever used
a list viewing application?
Okay, how many of you like this view?
Yeah, adapters can be a big, big pain points
when you have a slow-- in your UI.
It's very often the bottleneck of the performance
in the applications that use lists and adapters.
So we'll see how you can use adapters efficiently.
So first of all, this is what I have to say
They're awesome because they let you do many,
many really cool things
and they'll let you display various items in the list.
You can create ListViews in which every item
is a WebView.
If you do that, I will be very mad at you
because it's a really bad idea
in terms of memory usage and performance, but you can.
You can also do very simple things
like the contact application where you have a simple label,
like a simple line of text for every item.
Adapters are also very painful to use
because they introduce another layer of complexity,
another layer of abstraction in your application.
And the documentation kind of sucks.
That doesn't help.
But before you start--
before we start, I would like to know
if you guys know how ListView works.
How does the ListView use the adapter?
Raise your hand if you think you have--
you know how it works.
Well, some are more courageous than others.
I have a cool animation that will show you how it works.
So the adapter, like I said, is just--
Well, it's basically the man in the middle.
So you have your data source,
and the data source on Android
is very often just an array of data,
like an array of stream.
Or a cursor, like the cursor is something
that we use a lot on Android.
And then you have the ListView.
It's the widget that represents the data on the screen.
And the adapter is just this little piece of code
in the middle that takes the data,
converts it into widgets that then--
that are then displayed in the ListView.
It works very simple like this.
But in practice, the adapter--
the difference between the adapter and the ListView
is very complicated.
So there's this method called getView on the adapter
that you're probably familiar with.
So ListView for every position in your adapter,
so let's say you have a thousand items.
For each item that the ListView wants to display on screen,
it will call the getView method on your adapter.
And the goal of this-- the role of this method
is to return a view, a widget,
that will then be displayed by ListView.
And getView sometimes, very often in applications
that are poorly written, will return a new view.
And creating a new view on Android
is unfortunately very expensive,
especially if that view comes from an XML file.
Because you have to inflate it,
which involves reflection and tons of code is--
tons of code is actually invoked.
So we can't really create a new view
for every item you have in the list.
Now let's say you have a--
you're a crazy person and you have 2,000 contacts
in your address book.
If you want to scroll through your list of contacts,
we really can't create 2,000 views.
Like first of all, they wouldn't fit in memory,
but the time it takes to create all of those views,
it might be that 50 milliseconds per view
will slow down the scrolling by a lot.
So the solution to that is recycling views.
And here I have this really cool slide
that I had to create three times
because Keynote kept crashing,
so I hope you will appreciate it--
that shows how-- ListView recycle views.
So here we have a simple skeleton of ListView
that can display seven items onscreen at the same time.
And when the user touches the screen
and starts scrolling the list with his finger,
one item ends up outside of the screen.
So what we do is that--
so ListView now needs another item to display
the bottom of the list.
It could simply call the adapter and say,
"Give me a view,"
and the adaptor could return a new view.
But like I said, it will be very expensive.
Why do we need to create a new view
when we have this one at the top
that we don't need to use anymore,
because it's outside of the screen.
So internally ListView is this fabulous thing
that we call the recycler.
It takes the views that are outside of the screen
and sends them to the recycler.
Here you can see that there are several segments
because in a ListView, all the items can be
of the same nature.
They can be represented by the same widgets,
or they can be represented by different widgets.
So one item can be a text view,
another item can be a button.
And to do things efficiently,
the recycler is able to make the distinction between
all those different items.
So here, our item was the first type
that the ListView knows about.
So we put the item in the recycler.
And then that item is passed to the adapter.
So when we call getView,
there's a parameter called convertView by default
that is actually a pointer to that view in the recycler.
And when we do that,
when we pass one of those unused views to the adapter,
the goal of the adapter is to reuse that view
and simply send a text, change the image,
instead of creating a brand-new one.
So here, the adapter
turns out our old Item 1 into the Item 8,
and now ListView puts it back.
All the items are left unchanged,
and that lead--and that allows us to have very, very--
So if you try to fling through a list of ten items,
it will be the same amount of work for ListView
as if you were scrolling through
a list of 1 billion items.
So here's what you should not do.
So if you wrote code like that,
or if you have that kind of code in your application,
you should--at the end of the session,
you should go back to your computer and fix it.
So this is the getView method of the adapter.
So we pass the position of the item that ListView wants,
we pass this convertView we just talked about,
and the parent.
So the parent in this case is always the ListView itself.
And in that case,
you can see the first line of code in that method
I'm calling inflate, to inflate an XML file.
That doesn't look like a lot of work.
After all, there are only four lines of code
in that method.
But again, doing that while the user is scrolling
through a list of items would be very expensive.
It will generate a ton of garbage,
which will put a lot of strain on the garbage collector.
The garbage collector will then close your application
and you will see the scrolling stutter
as the system is trying to keep up with
what you are doing in the adapter.
So instead of doing this, do this.
Just check if the convertView is null.
So if the convertView is null, that means that it's probably
the first layout in ListView.
So then you can actually inflate the views.
You have to populate the recycler the first few times.
So it's okay to do this first inflation.
But if the convertView is not null, just reuse it.
You are guaranteed,
if your adapter is written correctly,
that it will be of the right type.
It will be one of the views
that you created from the adapter.
All right, so you can just cast it to whatever view
that's supposed to be in your adapter
and reuse its content.
So here, we're just setting
a couple of lines of text inside--
a line of text in an icon.
So the difference--
oh, in there, okay.
I'll show you numbers after that.
Even better, we came up with a--
we were working on improving the performance
of the contact application for 1.0,
and we came up with this cool trick
that we call the ViewHolder.
So how many of you have ever used this trick?
Okay, so some of you are good and read the blogs
and read the sample code,
'cause it's actually in the SDK.
There's an example of that.
It's called efficient list adapter.
So I think it's kind of clear what the sample is about.
Anyway, the idea of a ViewHolder
is to minimize the amount of work
in the getView method of the adapter.
Most of the time, your adapter--
even if you reuse the convertView,
you will notice that you'll end up doing
the same work all over again.
So if I go back to the previous slide here,
even if I reuse the convertView,
I'm still calling findViewById on the convertView
to get the TextView and the ImageView
that were inside my item.
So do we really need to do that every time?
So the idea of the ViewHolder is simply to hold some data
that's related to the item to the view that's passed by
the ListView and do the work only once.
So the way you use that is actually pretty simple.
So that's our third variation of the getView method.
We still inflate the convertView the first time,
and the first time, we also create an instance
of the--of this class, the ViewHolder.
So this is how we call this class,
but you can give it any name you want.
Usually we like to call the ViewHolder
so that we have a clear understanding of what it does.
So you create a new instance of the ViewHolder,
and you put inside any kind of data
or reference that you need and that you know
that you're gonna use every time getView is invoked.
So in that case, we do the findViewById the first time
and we store the result of that method call
into the ViewHolder.
And then we store the ViewHolder
as a tag on a view.
So a tag is any kind of object
that you can set on a view.
It can be used by your applications
to store some random data.
And in this case, we'll just store a ViewHolder.
You're pretty much guaranteed that the framework
will never use the tag automatically,
except in Cupcake on one particular occasion
which introduced a bug, so my fault again.
But if you set something in a tag,
you are guaranteed that whatever you set
will stay there and will always be of the type
that you just put there.
Now if the-- if we're past a convertView
that's not null, we need to reuse that convertView.
So the first thing we need to do in the L statement
is get the tag on the view, which is our ViewHolder.
We cast it, and then we can access directly
the TextView and the ImageView.
At first, it seems like this
would not make that much of a difference.
We're just avoiding two calls to findViewById.
But when I ran the three examples on G1 prototype,
this is what I came up with.
So the first example--
so the dumb adapter example, the thing you should never do,
and if you're doing it, then that's bad
and you should fix it.
We get less than ten frames per second
when we try to scroll through a list.
So that list in particular was showing you one icon
and one line of text per item in the list.
When you start recycling the views,
you can see that the performance becomes much better.
And in that case,
we get about 27 frames per second.
And when you use the ViewHolder--
so if you avoid doing this to findViewById on every--
every time the getView method is called,
then the performance goes up even further
and will reach 37 frames per second.
So just by using this very simple tricks
that add just a few lines of code in your adapter,
you can improve the performance
by three or four times very easily.
And again those are very simple tricks.
So once you've done it once,
you'll understand how it works,
and you will be able to do it
every time really easily.
Log in to save your progress and obtain a certificate in Alison’s free Fundamentals of Google Android Development online course
Sign up to save your progress and obtain a certificate in Alison’s free Fundamentals of Google Android Development online course
Please enter you email address and we will mail you a link to reset your password.