Google I/O 2012 - Making Good Apps Great: More Advanced Topics for Expert Android Developers


Uploaded by GoogleDevelopers on 30.06.2012

Transcript:
[ Applause ] >>Reto Meier: My name is Reto Meier, and I'm
the tech lead for the Android developer relations team.
In today's session, I will hopefully be able to provide you guys with some tips which will
help to turn your good apps into great apps. Now, I consider this to be a follow-up from
my I/O session last year, which was Android Protips, making this Android Protips II, Electric
Boogaloo. Like last year, I'm going to try and keep
things pretty technical. There will be code. So if you're not comfortable reading code
snippets, don't worry. I will give you this signal (indicating), which is your queue to
put on your headsets, start watching Transformers. So what makes a great app?
Well, in my view, a great app is one where users aren't even thinking of it as an app.
They're not thinking, am I using an app on a smartphone connected to the Internet over
a 3G network. They just want to perform an action, they just want to use a service. Whether
that's been clicking an icon, selecting a notification, clicking something on the home
screen, they just want to get something done and your app is just the way that happens.
So the idea here is to make them not have to think about the implementation. They don't
have to think about how you've done it, how the device is connected. Everything just works.
Let me give you an example of what I mean. A couple of years ago, I had the very good
fortune to visit Kenya. Over in Africa, mobile's a serious business. I don't mean serious as
in finding the best noodle bar in Nairobi. I mean serious as in this is the only way
you get online. I mean serious as in you go to a bar, you
see a cute girl or guy, and instead of sending them over a few drinks, you buy them mobile
phone credits so they can give you a call if they're interested.
Now, if your smartphone is the way you get online and it's the way that you flirt, a
really interesting thing happens to your perception of that device.
Let me give you an idea of what I'm talking about.
While we were over there, a big part of our G Africa or G Kenya event was finding out
and talking about the massive growth in smartphones' innovation and penetration across Africa.
So it was kind of surprising to hear that a lot of people didn't self-identify as Internet
users on their smartphones. We asked around, "Do you use the Internet on your phone?"
"No, not really." Well, that's strange.
"Why did you buy a smartphone if you're not using the Internet on it? Do you not search
for things and check your email and update your social networks?"
"Yeah, of course. Of course I use Google and Gmail and Facebook. I just don't really use
the Internet." [ Laughter ]
>>Reto Meier: So what's going on here? Well, it's actually a really interesting phenomenon.
And it's particularly the case in Africa where most people are starting to get online for
the first time using their smartphones. So people aren't thinking of these apps as
being really efficient ways of displaying a Web page on a phone. They just are thinking
of that's something I can do with this device. And that's becoming increasingly the case,
even here, where a lot of the most popular apps don't have Web sites. And if they do,
people don't visit them. The entire experience is on the phone.
So how big a deal is this? Well, while we were over in Kenya, we like
to visit some of the phone stores to find out what phones are selling, what kind of
tariffs, what's the deal. And we found that you can get the same phone
on basically the same tariff, and on the one hand, you can get unlimited social networking
updates. And on the other hand, unlimited Internet access. For the same price.
And the interesting thing is, the unlimited social networking updates was actually a more
popular plan. And so what we're seeing is people completely oblivious to the fact that
it's the Internet that powers this stuff. I'm sure if they thought about it, they would
realize. But the key here is that you've made that
disconnect. People are no longer thinking about how these things work. It's just something
that they want, and updating their social networks is something they do a lot, so that
becomes really valuable. So then how do we, as developers, create an
app that's more valuable than the Internet? Well, it helps if you've already got a service
that people really love, a service which they're already taking advantage of, and it's something
which they would use as a purchasing decision when figuring out what phone, what tariff,
what plan to use. Now, most of us in this room probably aren't
in that boat. We don't have the existing biggest service. What we're trying to create is the
next biggest service, the next biggest app that everyone has to have on their phones.
And I think a really good approach to being able to create that app is to build something
that works as though it were an indispensable part of the phone. So something that doesn't
drain your battery, something that's not obnoxious, that still provides all the information you
need exactly when you need it, but other than that, it stays out of the way.
And at the same time, it has to be absolutely reliable. It has to be something that users
can take for granted so they're never asking the question, should I do this? Should I have
a fallback? Because if they have a fallback in case your app doesn't work, they're just
going to start using the fallback instead. So I'm going to look at each of these topics,
invisibility, efficiency, and reliability in more detail throughout -- throughout my
session here. So if I seem a little bit nervous now, it's
because I've got a video queued up. And if you saw my session last year, I had a little
bit of trouble there. So it's with a small amount of apprehension that I queue up the
first of these interstitial videos. [ Video. ]
(Beeps). [ Laughter ]
(Lip-smacking sounds). (Noises, siren).
[ Video concludes. ] [ Applause ]
>>Reto Meier: Thank you. I can't take any credit for the videos. But thank you.
So invisibility. It's obvious why the Droid wants to be invisible. But why do we want
to make our apps invisible? Is this something we want? I think it is. And let me explain
why. So two things happened to me at about the
same time. I started working for Google, and shortly before that, I got my first Android
phone, a T*Mobile G1. Do we have G1 owners past or present in the crowd?
I/O audience never disappoints. You've all been upgraded today.
Those two things happened. As you know, the G1 had the Gmail app, wonderful app. What
you may not be aware of is that when you start working at Google, you start receiving email
at a rate of around 1,000 messages a second, give or take. And so to try and triage that
fire hose of information, I would check my email every morning as I commuted into London
from Wimbledon along the district line. So if you've ever had the pleasure of enjoying
that particular journey, you'll know that your Internet connectivity goes from kind
of spotty and intermittent as you go in and out of tunnels and stations until you get
to Earl's Court, London underground proper and your Internet connectivity disappears
entirely. Now, the beauty of the Gmail app is that I'm
totally oblivious to this. I'm checking my email. I'm reading them, hit archive, it disappears.
Send a message, and it goes. And I never have to think about whether or not I'm connected.
By the time I get back to my desk, open up your laptop, my inbox is synced, my sent messages
have all been dispatched, I'm ready to go. And I've never had to think for a moment,
how does Gmail work? How is it sending my emails? Is it connected to the Internet.
This is in direct contrast to one of the news apps that I've been trying to use at the same
time. So I could see the headlines easily enough. But if I were to click one to try
and read the article, if I happen to be in a station, it wouldn't load, or if I go through
a tunnel, then I'll get about halfway done and it will stop. So I'd be lucky if I could
read more than one or two articles by the time I got into work.
And that's the same kind of frustration as I feel when I navigate to a location and then
I look up the venue in an app, and as I'm walking down the stairs, I go to check in
and it's telling me, you don't have an Internet connection, so you can't -- try again later.
It's like, well, I want it now. I'm really not going to bother.
Straightaway, I've had this disconnect. I'm thinking about how does this app work, it
needs an Internet connection and I'm indoors now, so I don't have a cell connection. I
should try and get Wi-Fi. And it's a total disconnect. It makes me have to think about
how the app was written instead of what I want to do, which is simply check in.
So how do we create apps which are invisible, which let us completely ignore how they're
put together in the same way that Gmail works? Well, the solution is to use something like
this, a queue and send pattern. Now, the thing about this -- so let's have
a look at this. Before I go into the details on the code,
please note that all of the code snippets, slides, and everything else will be made available
within 24 hours of this. So don't try and copy any of it down.
But let's have a look at the code. So what we're trying to do here is, we check to see
whether or not we're connected. And if we're not connected, as in this case,
then we're simply going to add our transfer to the queue. So in this example, we're looking
at a check-in. So if we're not connected, that's it. If we
are connected, so looking at this next section, then we're going to try the check-in first.
If the check-in fails, then we're going to add it to our retry queue. Once we've done
that, we're going to go through that retry queue, which includes anything we've queued
up beforehand before we connected to the Internet and anything which has previously failed.
Anything that succeeds, we remove it from the queue and check to see whether or not
there's anything left in that queue. If there is, then we're going to need to try
this again later. Now, in this instance, I've created a fairly simplistic retry mechanism,
which is just going to use a set interval to continue to retry.
Now, this isn't particularly efficient. I'm going to give a much better example later
on of how you should probably do this. But for the purposes of this code snippet, it
gives you an idea of the process of what you should be doing.
Note also at the top, when we're not connected, we're also going to cancel this retry alarm.
There's no pointed in waking the advice and trying this again if we don't have an Internet
connection. And, similarly, or in relation to that, we're
also going to enable a manifest receiver, which is going to listen for connectivity
changes, so that when we do get back on the Internet, we can straightaway go through this
queue-up queue and perform all of those transfers straightaway, so you don't have to wait for
the user to initiate another action first. So that's one way of being invisible.
Another approach is to make sure that your app feels consistent with the rest of the
framework. Now, you want to be original, you want to
be creative. You want to have something which people are going to recognize and identify
with your app. But you don't want to have to give them that moment of cognitive dissonance
when they're trying to figure out how to use your app, how does it fit into the system.
So the real trick is to create something that is consistent with the framework aesthetic
but still has that creativity, still has that uniqueness that represents your app.
Now, the first step to that is to visit the design site at developer.android.com/design,
that has always the details you need both in terms of the specific implementation deals
as to how you should make your apps work, but also the philosophy behind it. So you
can think more about how are the Android designers thinking, how do they come to those conclusions?
I'm not part of the design team, so I'm not going to go in at any length here. But happily,
they will all be here tomorrow, basically all day, down in room 9, giving sessions,
interactive code labs, all of those sorts of things to try and really help you guys
get a feel for how they think, the decisions they've made, why they've made them and how
you can create something that, as I say, is unique and identifies your app but still allows
users to understand how they work without having to spend a lot of time on it.
So what else can we do? Well, I look at some of the most popular apps
and you look at things like Shazam, Instagram, they're hugely successful. And I think a big
part of that is because they've created something where it's tightly bound to an action. So
whether that's recognizing what music is playing or taking hipster photographs, you recognize
that action. You associate it with their particular app. And that's a really powerful thing. That's
how you get to that point where people just want to be able to do that.
And they don't care how it works. One of the real advantages to building something
which has that kind of tight focus is it makes it much easier to then port it across a variety
of different hardware. Now, this is important, because the Android
ecosystem is huge. You've got this huge variety of devices both in terms of variations on
smartphones and tablets, but also an increasingly wide and diverse ecosystem in general.
So most of us have spent a lot of time developing for smartphones. And that's where a lot of
our focus lies. Now, smartphones have all of the new gadgets.
They've got all the sensors, they've got NFC, they've got touch screens, gyroscopes, front-
and back-facing cameras, the works. And so it makes sense to develop your app to take
advantage of all of that hardware. But then what happens when new hardware comes out?
You've all got a Nexus 7, you've probably noticed it doesn't have a back-facing camera.
What does that mean to us as developers? Well, the easiest step is to say, well, my
app takes advantage of all these different sensors, so I'm going to add lines to my manifest
which says it requires an accelerometer and NFC and everything else I take advantage of.
Then someone releases a device which is slightly different, and suddenly your app isn't going
to be available in Google Play, and you're cutting off what could be a significantly
large portion of your potential user base. Now, you want to avoid this. And so let's
have a look at a couple of examples. So for -- if you've got something like an
accelerometer, something like a compass, which depends on an accelerometer to figure out
which direction you're facing, it's pretty easy to say that is a required hardware feature.
What if you have an app which lets you apply filters to photos? Do you need a camera for
that? Well, most of these apps you don't, because you can apply those same filters to
photos that are already on the device or that are in your gallery. But by simply adding
this service requires users feature to your manifest, or even in the case of camera, just
using the users permission and not saying that the camera is optional will prevent that
app from being available to these devices. So a much better approach is to use the Package
Manager to see what hardware is actually available at run time. So rather than blocking your
app from a potential user, what you're doing instead is saying, well, the user experience
is going to be different. So that can be something as simple as saying,
well, if there's not a camera, then I'm going to disable or even hide, remove, the take
a picture button. That makes sense. But it could be something much more dramatic. So
you may say, well, if there's no touch screen on this device and no sensors, then I'm going
to try and present more of a lean-back experience, something where I'm expecting people not to
interact with this app as much. And so by using this Package Manager class
at run time, you're able to figure out exactly what hardware is available and really customize
that user experience to present the best possible way of being able to do things. It really
comes down to, rather than trying to say how do I lay out my screen on these different
size devices, instead, what you're figuring out is, given this hardware, how can users
best perform the action which they're expecting to be able to do with my app?
So it all gets back to this simplification, making it invisible, making it more accessible
for your users. So that's invisibility. I'm going to move
on to the next section now and spend a fair amount of time on this, because it's a topic
that's really close to my heart. I think efficiency is really important for users.
So let's have a look at the video. [ Video. ]
(Ringing noises). [ Video concludes. ]
[ Applause ] >>Reto Meier: So efficiency. We all know that
efficiency is important. It's one of the key tenets of programming. So it's a huge topic.
And today, really, I want to focus specifically on efficiency in terms of improving the battery
life of your apps or reducing the impact on the battery life from your apps.
And even more specifically, I want to look at how your use of the cell radio, so the
way in which you transfer data, can impact on your battery life.
You guys already know about my email habit. I absolutely require email access all the
time. And if you add to that apps like Pandora,
Google Music, maps, all the other things which I take for granted, if I don't get eight to
12 hours of battery life out of my phone, it's a serious inconvenience.
I can see a few folks in the audience, you're thinking eight to 12 hours, is that a Jelly
Bean feature? Are you running Cyanogen. It's none of that. Really, the way I achieve
it is, I'm absolutely brutal when it comes to removing apps that disproportionately drain
my battery. So if I install something, look at it once,
and then find at the end of the day my battery life hasn't lasted as long as it did before,
I'm going to remove the new app. It doesn't matter how useful it is, it makes my entire
phone less useful, and so it's going to go. And when you're performing that analysis,
figuring out which apps are the worst offenders, it turns out that the way that they use the
cell radio is actually a big impact. And you can see that when you've got your cell phone
on and you're using cell data, it can be a significant battery drain.
So how do we impact that? How do we reduce the impact of that battery?
A big part of that is quite simply transferring less data. So smaller pay loads, less-frequent
updates, just generally send less data. Now, I'm going to look at a few specific techniques
for improving that side of things as well. But first, I just want to think, is there
anything else we can do? Does the timing of your transfers impact the battery life?
Turns out, happily for the length of my talk to the answer is yes, it can impact it. And
it results in a scenario that I like to think of as the cookie Droid conundrum.
So I like the cookie Droid, we need to think to ourselves, would we prefer one big cookie
or lots of little cookies? Or to put it in slightly more practical terms, do we want
to have as many -- have lots of little downloads so that we're only downloading data that we
absolutely need, never downloading anything we don't? Or do we have one -- or as few downloads
as possible, we're downloading lots of information, potentially more than we need, in order to
have fewer downloads overall? A quick straw poll. Who likes one big cookie?
All right. And who's into lots of little cookies? All right. And who thinks we should just go
like the cookie Droid and eat all the cookies? Yeah. Sadly, my metaphor does not extend that
far. So we're going to have to look at the two remaining options that we have.
So the little cookie at first glance seems like a fairly good approach.
You're not going to download anything that you don't need. So you're minimizing bandwidth.
You're not processing anything that you don't need, so you're going to save some power on
the device that way. And, really, what it comes down to is, you're
going to put everything off until the last minute. You're not going to do anything until
you're absolutely certain that you need to do it.
And that's an approach that I used pretty extensively getting through college. Now,
-- [ Laughter ]
>>Reto Meier: -- as it turns out, both in terms of college grades and in terms of cell
radio efficiency, it's actually not a very good idea. It's just going to cost you more
in the end. And a much better approach is to use this
big cookie model, minimizing the number of times that you touch the network, the number
of times that you have to perform these downloads. And to understand why that is the case, you
need to understand a little bit about the way that the cell radio works.
So this is a really simplified version of a typical 3G cell radio. And it works this
way. So you start off in standby mode. And every time you try and start a new connection,
transaction data, it's going to take around two seconds -- this varies, but around two
seconds -- to bring the radio up to full power, at which point you can start transferring
data. Now, if this is a browser, you can imagine,
this isn't a great experience. If every time you click a link, hit refresh, hit some JavaScript,
you need to wait two seconds before the radio powers up and you can even make the request,
let alone download the data, let alone render the data. And so to try and account for that,
the cell radio will stay in a full-power state for some amount of time, typically somewhere
between five and ten seconds, and what we call a tail time.
So within that time frame, the radio is still kept in high-power state, so you have latency
if you want to perform further transactions. After that tail time has expired, you go into
this low-power state, draw about half as much power, and the latency is going to be reduced.
It's still going to be there, but it's going to be significantly reduced.
Now, we're going to stay in that low power state for somewhere between ten seconds to
a minute. And, again, if nothing happens after that period of time, we go back into standby
state, where we're not drawing current, but we've introduced this latency.
Now, the specific tail times are going to vary based on carrier. So that's going to
be not just carrier, but location, so East or West Coast, different countries, different
carriers, different usage patterns for their customers and everything else.
And so AT&T has a -- timings like this: Five seconds for high-power tail time, 12 seconds
for low-power. Vodafone has also five seconds for high power and a full 30 seconds.
Now, I should point out that there's no better or worse. These are just different ways in
which these companies have figured out the most efficient patterns for their users in
those locations. And it goes on and you can imagine it's the
same for Verizon, and T*Mobile and everyone else.
So how do you, then, as a developer figure out the best frequencies, the right timing
to do your downloads in order to have minimal impact on the battery?
Well, everyone here is an engineer, so I assume everyone's familiar with fast Fourier transforms.
So we're going to start with this basic equation. And then what we want to do is, for each carrier,
find the square root of the sum of the squares of those delta tail times, divide that by
pi. So who's still with me? Got a couple. It's very impressive, because
this is totally made up. [ Laughter ]
[ Applause ] >>Reto Meier: If you can see my afterwards
and explain, that would be fantastic. [ Laughter ]
>>Reto Meier: So like I said, this is irrelevant. You don't -- it doesn't matter. It doesn't
matter what the different tail times are. It doesn't matter what the variation by carrier
is. All you need to know is that every time you
touch the Internet, every time you make a connection or do a transfer, you're potentially
going to continue draining battery for a full minute. Just think about that. So if you touch
the Internet just to do a ping, just to say, yes, someone is still looking at this page,
the cell radio is going to stay on and continue draining battery for up to a minute.
This is much easier to understand if you have a look at the visualization.
So what you have here, in blue, the blue line graph represents network traffic for my app.
And so you can see the little periodic updates, about every 15 seconds, and then we have these
larger sort of intermittent transfer. So this could be a news app, where the periodic transfer
is analytics. We're keeping track of what page, what articles people are reading at
all times so that we can get a feel for what the most popular news articles are.
And the intermittent transfers, they may represent someone clicking an article, all right. So
they want to read the full text, you click it, download it and read it.
What's more interesting is underneath. That represents the cell radio state.
Now, blue is an active transfer. This is when we're actively sending and receiving data
from our server. Red is that tail time, that high-power tail time where the radio is still
drawing full current, but we're not actually transferring anything. And that will last
for around five seconds, in this instance, exactly five seconds. So you can see right
at the beginning it was on. Then we started another transfer straightaway. So it's continued
in that high-power state. If five seconds elapse, it will turn yellow.
That's when we're at that low-power state. And it will stay there for a further ten seconds,
assuming no one performs any transfers. Now once that time has elapsed, you'll go
back to the idle state. And that is represented here in green.
Now, you probably notice the problem. There is no green. Right?
So the entire time that this app is running, it's drawing power from the battery. And you
can see, it gets worse than that. Because even just this section in the middle, where
it's just the periodic transfers, we're still never going green. So even without the user
doing anything, you're still going to be drawing current, reducing your battery life, just
by having the app open. Now, this is exactly not what you want. So
how do you solve this problem? Well, I like to think of it as defragmenting
your network traffic. What we're really trying to do is use a combination
of different things: Prefetching, bundling, basically trying to perform this big cookie
model, do as many things we can every time we touch the Internet so that we reduce this
intermittent touching so we have less and less time spent draining the battery.
Now, I'm going to explain how you can do that. But, first of all, I just want to show you
exactly what I'm talking about. This is the same data being transferred, the same amount
of data, but everything has been batched together. So those periodic pinnings, those Analytics
updates, you've just batched them up and I only send them when I have something else
I need to do. When they get sent isn't important. Now, instead of having on-demand downloads
for the news articles, I'm going to prefetch them. I wrote this app, and I happen to know
through my Analytics data that people read exactly two articles every minute and I happen
to know exactly which two articles those are. So that's made it really easy for me to be
able to do this prefetching routine of two articles a minute.
This is pretty contrived. But it's actually contrived in a way that makes it not as effective
as it could be. In a real-world solution, you can have this window extend far further
than the few seconds that I have here. But even with this contrived and basic solution,
you can see the impact is pretty dramatic. Straightaway, you've gone from having no green
to having almost two-thirds green. Even the active traffic has been reduced because we're
able to be much more efficient in the way we download our data by doing it all in one
go. So we've reduced both the active time and
the standby time so that we really are in a much better situation here, where the app
is not going to be draining the battery for anywhere near the amount of time that it was
before. So how do we create these graphs? How do we
figure out what our app is doing and how to make it better?
There are a number of tools available for doing just that.
On the most basic level, you can use logcat. So you can just print log statements before
and after you started doing your transfers, potentially even keep track of how much data
you're transferring each time in order to build up these graphs and this idea of how
your app is behaving. Another option is the arrow tool, which is
a free open source tool available from AT&T, who I think are actually demoing it out in
a sandbox. You should stop by and say hi to them.
The advantage of their tool is that it's going to produce graphs very much like the ones
I showed in the previous slide. So they're going to show you your network traffic and
they're going to overlay your radio state, specifically, the AT&T timings.
Another approach, which I actually quite like, and this is more recently available, is the
network statistics tab in the DDMS view of your Android developer tools. That's the app
that you can see here. This colorful graph. So this lets you tag different sockets, different
parts of your app so you can see how they're all interacting, as you can here, using different
colors. And you can do that using the traffic stats class.
This is a relatively new class. The beauty of all of this stuff is that you can use it
on your app even if you're targeting early versions of Android. You can do this analysis
statically in the emulator. So you can do this for -- no matter what your target is,
even if you're not targeting later versions of Android, you can still perform the analysis.
So the way this works is, you simply assign a tag to each of your output sockets. They
color code it, and you're able to see exactly how your app interacts with other components.
And you can look out for patterns, which I'm going to go into a little bit more detail
on. If you're not using sockets directly, if you're using an HTTP client, then you can
simply set the thread stats tag on the thread itself, and that will automatically be assigned
to the socket used by that HTTP client, making life a little bit easier for you.
So now you've got the grass. The next step is, what are you looking for. So the first
thing you're looking for is these short spikes. So this represents -- each of these spikes
is one second. And so we're looking for both short in terms
of height and in duration, particularly duration. Because here we are downloading for a second.
And each time we do that, the device is going to be drawing battery for a minute, so that's
a really bad deal. So you want to look for anything like that and typically these are
going to be good things which can be delayed. They can be bundled up. They can be queued,
so you can download them in all in one go later.
Another really bad sign is anything periodic. Anything which is happening on a set basis
because this stuff is basically guarantying a minimum amount of time that your app is
going to be drawing power. That's not what you want. The minimum possible time that your
app should be drawing power from the cell radio is zero. The user is doing nothing,
it hasn't done anything. It shouldn't draw any power. This is a really bad sign. Slightly
less concerning but still an area that you can look to improve is these batches of activities
which happen in close proximity. So here they are not unreasonable transfers but there's
this gap, this few seconds between each of them. And in that gap, we are still drawing
battery, so just by pushing them together, we can have that incremental improvement.
So let's have a look at some solutions. What can we do to try to improve this to defragment
our traffic? One of those approaches is prefetching. Now, what you've got to remember is that when
the cell radio, when the carrier are working out what is the right timing for these tell
times, this is what they are trying to balance. Minimize the latency and minimize the battery
life. One plays off against the other. They don't have a choice. This is the graph they
are on. From our perspective, from our user perspective, this is exactly the wrong graph.
We don't want that. What we want is to hit this sweet spot. Where we have got basically
zero latency and maximum battery life. That's what we are trying to achieve. Now, the idea
of prefetching, you kind of get the best of both worlds. If it is already downloaded,
it is already processed, then you don't need to wait for it to process it again. At the
same time, if you've prefetched it, if you've bundled everything together, you are not getting
this spike, this intermittent download, in the middle your app's life cycle. It's already
there, and you can much more manage the frequency of those downloads. Now, unfortunately, prefetching
isn't a silver bullet. There is a risk. There's a risk that you will download a bunch of data
that you don't need. That's going to drain the battery just as sufficiently or just as
effectively. So how do you make that balance? Well, generally what you want to do is make
sure that whatever you are going to download is going to be used by the app. What you're
trying to avoid doing is downloading something that you know you are going to need later
so you do it ahead of time. Typically, that is somewhere in the realm of two to five minutes.
Now this depends on your app, the way that it's used. A lot of apps have sort of this
two- to five-minute window where they expect people to use them. If you have something
like a music player, the window may be significantly longer. The amount of data is also going to
vary. It's usually somewhere around one to five megs, but this is going to vary on the
cell radio technology, its effectiveness, as well as your app. Practically speaking,
if you've got something like a music player, you probably want to download the currently
playing song in its entirety and probably the next song as well, but probably not the
play list, probably not the album. All right? If you have got a news app, you can be a lot
more aggressive. We are talking about text. Text is cheap. You can download heaps. You
can download all the headlines and all of your categories. You know what, you should
probably download some of the article text as well. You can either do this simplistically,
say, well, this is my front page, I'm just going to start prefetching things based on
when they appear to the user. You can be a little more clever and use Analytics. 70%
of the people who use my app read these articles. I'm going to prefetch them for everyone. Or
make it more personal and say this user always reads all the sports articles, I'm going to
pull them out. Really, it's just a matter of trying to figure out what is most likely
to be used so I don't have to pull it down later without pulling down things that isn't
going to be used. I mentioned this is for 3G, these specific timings. The thing is,
it changes depending on the cell radio that you are using. They have different efficiencies.
They have different speeds. In this example, we will start with a default
based on a 3G network radio. There's a lot of code here, but it's effectively just a
couple of switch statements. All we are doing is checking, what is your network technology.
If it's 4G, then we've got two things at play. These radios, they tend to drain a little
more battery than their 3G equivalents. They are also faster, so you can download more
over the same time period. If you are trying to balance the cost of the device going to
be drawing current for a minute, so I want to download for at least ten seconds, you
want to download more on a faster network. The reverse is true for 2G. It's slower. It's
slightly more energy efficient. So you want to download less data. Now, the specifics,
I've gone times 4 times 2 is kind of arbitrary. This is something you need to figure out within
your own experience what makes sense for your data and for your app. The key here is to
remember it is going to vary. This is especially the case with Wi-Fi. So on Wi-Fi you don't
have a cell radio cost associated with performing these downloads. You can be much more aggressive.
In this example, I've simply said download the maximum amount that we can to put in our
cache. This is going to be much more dependent on how much data do we want on the device,
what's the relative cost of processing, rather than cost of putting things on the network.
So that's fine for apps, for data that we know we are going to need. You can prefetch
things if you know eventually it's going to have to happen. But what do you do about things
that happen which are user initiated, things which you don't know you are going to need
ahead of time because they are going to change because the user has created them while they
are using the app. The key here is to try and bundle them all together. You are trying
to be as efficient as possible. You're not -- you are bundling them, batching them, you're
doing whatever you can, trying to make sure they aren't draining the battery when you
don't need them to. One solution for that is to use a batch queue for anything periodic.
So this is for things which user created by aren't time sensitive. So Analytics are a
great example of this. Anything where you don't need the server to provide you a response,
you just need to upload it at some stage. They work really well here. So you can see,
in this example, what we are doing is every time we have something periodic, which we
want to send to the server, we will add it to a queue, and then we are going to execute
that queue at a certain point. You know importantly here, that when we do execute that queue,
when we transfer these all these bundled periodic transfers, we will also execute the next prefetch.
That may not be scheduled to happen for another minute or two. But hey, we have the radio
turned on, why not, right? Do it all now. Get it out of the way, and then we don't have
to turn the radio on again later. The same thing is true when you have time-sensitive,
on-demand transfers. So when your user is uploading a photo or if you want to get feedback
directly from the server, it needs to happen then and there. That's no reason not to bundle
everything else together as well. So when you do have these time sensitive transfers,
you execute the next prefetch. When you do that, you execute your periodic transfers
as well. It all comes back to the same underlying philosophy. Every time you touch the Internet,
do everything which you think you may need to do for the next few minutes at once.
That's all good and well. But what happens to the data that is server side but you still
need to get regularly updated? So you have a news app and you want to get new headlines
or weather app and you need to know what the current temperature is. These are things which
traditionally you're going to do by polling. How can we make this a more efficient process?
Fundamentally, we want to make it less frequent and less regular to try to get away from the
bad patterns we have seen earlier. First thing we can do is everyone's favorite, inexact
repeating alarms. It wouldn't be I/O if I didn't present this slide. Basically, this
will going to let the framework do what we have been talking about for us. It will phase
shift our alarms so all the downloads at the same time as other apps download around a
similar time frame. Rather than each app waking up the device every five minutes, it all happens
at once. This is a good start. But it's pretty simplistic. So what else can we do? One approach
is to use what I think of as an inactivity back-off. So what's happening here is we will
set a default for how often we should do our background updates. Now, if you've had to
do this, you know this is a balance. This is a payoff where you are thinking, how frequently
can I do these updates so that the data is as fresh as it can be but we are not draining
the battery by updating every five minutes in the background. It's always this balance.
What I'm suggesting we do here instead is to say, well, let's start with that. But if
the user doesn't open the app since the last time we have done a refresh, that was wasted.
Let's wait twice as long next time. They still haven't touched it, wait twice as long again,
so on and so forth. If they exit it and never look at it again. Hopefully that doesn't happen.
But if it does, your app isn't going to drain the battery. They don't have a reason to uninstall
it. I think this is a really good alternative to trying to create that sort of -- that solution
where you are trying to find that balance. So that's something we definitely should consider
as a default. Obviously, it's always useful to have an option for uses to manually set
every fresh frequency, to say, well, actually, I want it to be more or less frequent than
this. But this is kind of a more efficient way of being able to do that first step.
So I also mentioned early on that my retry mechanism was overly simplistic. It was inefficient.
I learned this the hard way. A few years ago I built a widget for Google desktop. Anybody
remember Google desktop? What this did, it's great for a cricket info website to get test
match cricket scores. As everyone knows, the fate of a match can hinge on a single ball.
I had an aggressive update frequency of every minute. Every minute I would hit the server
and scrape the web page, find out the score. I would look for a little string that would
say the match had completed at which point I would stop doing my updates. This worked
really well. I was a friend of mine who was beta testing it at work. He went home on a
Friday before the match finished. By the time he came back on Monday, he got the 404 page.
That's a pretty busy 404 page. In fact, it's 131K of 404 page. I was hitting that every
minute for every hour every day. After a week, we've got one and quarter gig of download
which he discovered when the net ops came past his desk to see if he was doing bit parenting.
Imagine this on a mobile device. 4 gigs a month, that sounds -- or 5 gigs a month. That
actually sounds a like the fair use quota use for tariffs. This isn't good. If you have
a simplistic 404 page or API which returns with an error code, your data is going to
be a lot less but you're still doing periodic updates, you're still going to drain the battery
just so the app knows something isn't working. Not a good approach. Solution here is that
same back-off. Exponential back-off. Here I'm doing it using a recursive algorithm.
For your apps, you will want to use something like alarms. The key here is that, if it doesn't
work, wait twice as long next time and keep extending that. On a phone, you probably want
to get to that maximum interval, say, you know what, it's not working, forget it, show
something to the user, do something within your app to account for that. There's no value
in continuing to try something that clearly isn't working.
Now, what's a better alternative to this background polling, trying to make that more efficient,
is to use Google Cloud messaging instead. This has been re-released now. Eliminate polling
completely if you have control over the server. So you just register your device to your server
into Google Cloud messaging. Instead of you polling the server, the server sends your
device direct messages when it has something to update. This is so much more powerful because
you're no longer trying to figure out that balance between how often should I ping the
server to check to see if there is something there in order to provide fresh data. You
just get told by the server when there is no data. Then you can make a decision as to,
do I want to download that now. Do I want to wait until the next prefetch interval.
What is that data? You can send all that information and provide a much more efficient solution.
So I'm not going into too much detail. The key to it is it is available back to Android
2.2, 94% of the devices. In addition to all of these new features, it has a significantly
simpler authentication story using API key. So it is much easier to use on the server
side if you're not a server side developer, which I'm not, so this was a big thing for
me. It's -- actually the next session done in room 9 downstairs is all about Google Cloud
messaging. If it is of interest to you, it should be if it isn't, definitely go and check
that out. So this kind of goes without saying. I'm going
to say it anyway because it seems fitting, redundant downloads are redundant. Don't download
anything you have already downloaded. There's a few ways you can do that. You want to make
sure you filter anything on the server. Use APIs, which will let you say there is the
last piece of data that I got. Or this is the last time I did my updates, so only send
me things more recent than that. So that's kind of fundamental. Then you're not having
to process things, not having to download things which you have already downloaded in
the past. The same thing goes for any processing that you are going to do on all of that data.
If you download an image and you're going to display it as a 72 pixel thumbnail, there's
probably no reason to download the full wallpaper. Much easier, more efficient for you to be
able to do that stuff on the server. Much easier to throw resources on server side solution
than to hope all your users are going to buy faster, better phones. So anything you can
do server side, do it server side. When you have downloaded it, make sure you cache it.
Cache everything. You have a couple of alternatives. You can store it in the external cache. Now
this requires a new permission in Jelly Bean to write to the external storage. It's also
(indiscernible) readable, so it's kinda awesome. If you use the internal cache, that's going
to be within your application sandbox, so it's going to be controlled by you. It's going
to be also managed by the system, which means if it becomes under resource pressure, it's
going to be able to clean out your cache in order to save it some room. This is the best
approach. Another thing you can do is make sure that
you don't download anything that you don't have to. So you can do that by inspecting
the headers of your http responses. So you can check when does this data expire? When
was the last time it was updated? Do I need to download the body here? When should I try
and update all of this information? So that can be really useful. Even better is that
in Android 4.0 we introduced a http response cache to the http URL connection class. So
this is just using a reflection to turn on a 10 meg cache on a http URL connection. What
this does is it is going to do all of the stuff that I just explained for you. It's
going to create his own cache, inspect the expired headings and every time you make a
request, it is going to check to see whether it already has that data and whether or not
it has expired. If it has it and it hasn't expired, it's just going to serve you from
the cache and put it into the cache automatically for you. This is a really neat trick to be
able to take away a lot of that hard work from you.
So that's almost done with efficiency. If you want to have all of this information without
my strangely monotonic Australian accent, it much easier copy/paste code snippets, then
you can get it all from the developer training site at developer.android.com/training. It
will be all there for you. I've spoken in this section about efficiency,
specifically about battery life, specifically about the cell radio. Jeff Sharkey is doing
a session in this room at 4 o'clock today which is going to cover a whole bunch of other
efficiency things you can do with CPU, with memory, with I/O, definitely check that out.
So we have a few minutes left. I've got one last section, this will be the shortest.
[ Video ] [ Applause ]
>>Reto Meier: Relatability is something we all want. If your power stops power your devices,
if your water starts running, it's kind of a big deal. But if it works, you just totally
ignore it. And that's exactly what you want. You want to be able to take these sorts of
things for granted. So how can you do that? How can you create an app which is properly
reliable. So part of that is static analysis. You can use tools like Lint, like strict mode
will let you have a look at how your apps are working. I kind of like to think of these
as a lot like a peer review. Someone who already knows all of the right stuff, probably the
same stuff as you, maybe a little bit more, and they are able to give you code a look
over to tell you whether or not you are doing the right thing. Now, so, yeah, basically
a peer review but without the self-loathing and recriminations that so often accompany
a good peer reviewing. Once you get past that though, you really
need to see how your app is going to work on devices, that means buying devices. There's
thousands of Android devices, certainly no one is going to expect anyone to buy all of
them, certainly Google hasn't. So what is an alternative solution? Well, one thing from
talking to developers trying to solve this problem is find ways to separate that market.
Now, what I've done here are separated into buckets in terms of screen size and screen
resolution. Now, this is no longer the way that you should be designing your screen layouts.
You are not trying to design screen layouts in terms of these buckets. You are trying
to use minimum screen widths and make sure that you create an app that scales within
those bounds. But in terms of choosing apps, choosing devices to test your apps, this is
actually still a pretty good approach. So you are now down to 16 buckets. As you choose
each of the devices from that, you want to try and create something that is as varied
as possible. So you want to get devices with different GPUs, different manufacturers, some
which have cameras, some which have slide-out keyboards, touch screens, et cetera, et cetera,
and that will give you a nice cross-section to test with. That's kind of still a lot of
devices. So if your budget is a little bit more limited, you can kind of focus on the
areas which are going to represent the largest part of your audience. So you can see here
that that pretty much comes down to smartphones and ten-inch tablets at the moment. This is
based on the numbers on the Android developer site. And that will give you a pretty good
coverage, right? That's only three devices. The only problem here is that you're actually
possibly limiting yourself. What comes next? These are the devices that are out there now.
But you all have Nexus 7s now. At $199, I feel there will be a bunch these devices in
people's hands. Plus all the new smartphones are running XH DPI so the Galaxy Nexus, HTC1X,
Samsung Galaxy X3, they are all running these extra high res displays. While this is a little
bit of guesswork, you can usually take a pretty good guess as to where the next big buckets
are going to be and perhaps invest in those as well. You guys are lucky, you've already
have those last two buckets given to you today. So that's going to make life a little bit
easier. So you've done your testing on your hardware.
I did mention that that's not the right way to do multiple screens. The right way to do
multiple screens is on the developer.android.com training site, so do check that out.
Beyond that, for the devices you haven't got, use monkey runner. Use the emulator. Try out
as many variations as you can. Get alpha testers. Get people who you know. Don't get your smartest
techy friends. Get your least techy friend. The guy who you have to help him get his phone
out the Swahili every other week. That is the guy who is going to find the edge cases,
push 7 buttons at the same time and wonder why it broke. That's the person who you want
testing your apps.
So, if there's anything we've learned from IO this year and the keynote yesterday, is
that Android is a lot more than a smartphone development platform. Certainly the huge,
huge user base of smartphones means it's going to be the focus for a lot of us. But with
new devices like these tablets, like the Transformer Prime and the Nexus 7, we are seeing this
increasing ecosystem. If you guys have had a chance to hack around with your Nexus Q,
you see the potential is that this ecosystem is going to grow further to devices more and
more varied, more and more different. But fundamentally, hopefully, if you create an
app that uses the achievements of invisibility, efficiency, and reliability, you will create
something so that it doesn't matter what users are using, which device they are operating
with. They are not using the Internet on their phone, they are using your app. Thank you.
[ Applause ] >>Reto Meier: So then we barely have enough
time for a couple questions. Before we dive into that. I wanted to give a quick rundown
on what I used to provide this presentation today. I got a lot of questions about that
last year. I'm actually using two devices over here. You have a Nexus 7 and a Transformer
Prime. I've hooked them up so that the Transformer Prime is doing all of work. I have a HGMI
cable which goes up to the projector. My clicker plugs into it. I have an Internet connection
to send off stuff to the social networks and I have a Nexus 7 over here which is where
my speaker notes are. Today actually they hooked it up so it shows up on my conference
monitor down there. So, yeah, we do have a couple of minutes. So questions? There's mics
down the aisle. >>> Check check. Thank you for your presentation.
And I'm Bo Stone from Bo Stone Consulting. So here's the question. Is there an easy way
to detect that the radio is, in fact, on and so would it make sense to check that before
I do that batching that you were referring to?
>>Reto Meier: That's a good point. That's something that would be useful. There aren't
any APIs at the moment that allow you to say perform this the next time the radio is on.
You basically want something like the passive location provider but for transfers. Unfortunately,
no, there's no API for that at the moment. >>> Maybe you guys will add it in the future.
>>Reto Meier: Definitely something to hope for.
>>> Thank you. >>Reto Meier: No problem.
>>> Hi, can you comment on the CPU battery life trade-off of compressing a text file
before sending it versus sending it uncompressed? >>Reto Meier: That's a good question. So I
think the battery life impact on doing that compression is going to be pretty negligible.
The processing cost of that is going to be pretty slow whereas when you are doing that
transfer, like not only is it a shorter amount of time, it is less pressure on the networks
themselves. Big part of that as well. I focused on the efficiency side. Talk to the carriers,
it's really important for them to get payloads as small as possible, let the networks more
efficiency. That's going to end up in a much better result in your uses as well.
>>> Thank you. >>> Thanks for the presentation. Regarding
the earlier part of the presentation, do you have any idea if Google Analytics pays attention
to sort of all your recommendations? >>Reto Meier: That is a good question. So
the existing Analytics SDK allows you to dispatch your Analytics information whenever you want
to. So that allows you to have that control. I think it's something that I've just actually
been having conversations with them now to find out exactly what they do and what they
don't do in terms of automated downloads. Something they are aware of. We will go from
there. >>> Cool, thanks.
>>> My name is Rob. I want to know if the http response cache class is useful for caching
images or just for small http responses because I found caching images especially with, like,
downloading background threads to be a really challenging problem when you are downloading
a lot of things at once. >>Reto Meier: Absolutely. Downloading images
is definitely a challenge. I would say the http response cache, I had to practice a long
time to be able to say that. It probably could work but it's probably not the most efficient
way to deal with that, so there's -- I think we talked in the fireside chat yesterday that
there is a library which we will be releasing at some point that try to say do it in the
most effective way. There's an Android training class as well.
>>> I am really looking forward to that library. >>Reto Meier: I think you are not the only
one. >>> So you comment to use Cloud messaging
service to push messages, right? But I'm wondering, so particularly a window sign into any -- so
what is the plan for those little percentages of user who don't sign into any account. So
what is the plan that -- how we can push messages to that user.
>>Reto Meier: That's a good question. I'm not a hundred percent sure on the answer here.
You will want to check with the GCM team who are doing a talk next. I have a suspicion
that GCM doesn't require a sign-in, it requires the GMS services to be on the device.
>>> You mean to say this is different from C2DM, shore for user sign-in.
>>Reto Meier: C2DM did. I'm not certain, so please do check with the team. I have a suspicion
that that may have already been solved. >>> Maybe you can give me some contact.
>>Reto Meier: Absolutely. Come out to the office hours and we will hook you up with
the right people. >>> Hi Reto, great session.
>>Reto Meier: Thank you. >>> Are you aware Google http library which
also does exponential back-off, retry handling, caching, would you recommend that for development
in Android? I think it's compatible with Android run times.
>>Reto Meier: No, I'm not family familiar with it, so I can't really comment. That's
usually a good sign, but I couldn't say. I'd have to look into it before giving an opinion.
Thank you very much, everyone. [ Applause ]