[MUSIC PLAYING] CHET HAASE: Hello. Welcome to another talk. Welcome to Modern
Android Development. I should point out,
before we start, that this sun is a lot
brighter than I am, so we may have to do this. ROMAIN GUY: So we can
either put on the glasses and not see the slides, or
don't put on the glasses and not see anything. So that's going to be fun. CHET HAASE: We'll see
how this goes today. Welcome to Modern
Android Development. I'm Chet Haase from the
Android toolkit team. ROMAIN GUY: And I'm Romain Guy
from the Android framework team slash something. CHET HAASE: And we're going
to talk about a bunch of stuff that you probably already
know, but it occurred to us that we have given you advice
and information about how to develop good apps for
Android over the years. And that information has
changed over the years as we've introduced new
capabilities, new APIs, new performance on the
platform, all kinds of things. And so it's a little confusing. You could go search
for information even on some of our
docs site, and maybe get information
that doesn't really apply to a lot of
situations currently. So we wanted to
wrap it all together and say, here's our current 2018
view of the important things to think about in Android. ROMAIN GUY: Android is
10 years old this year, and yeah, like Chet said, a
lot of outdated information. Sometimes, I see blogs
on stack overflow, someone being really
mad about something that we said 10 years ago. Don't be mad. It's OK. Things change. Things evolve. It's not because we hate you. It's not because we were wrong. It's because it was a different
time-- different needs, different devices. So we're going to talk
about some of that. Just to make sure you
understand the difference between the modern
way of doing things and the old way of
doing things, we have a slight hint
on the slides. So some of the slides are
going to look like this. CHET HAASE: So let us begin. So let's take a
look at a timeline. This is sort of all the
history of Android over time. So 1.0 came out
in 2008, and then apparently, we didn't do
much for several years. [LAUGHTER] I don't know what
was going on there. I just couldn't think of
the things to put in there. Optimize, optimize, optimize. And then Android
Studio came out. What's that? ROMAIN GUY:
According to the web, we were busy building bad APIs. [LAUGHTER] CHET HAASE: Apparently, those
weren't the ones you wanted, so we've worked better
at that over the years. So Android Studio came out,
so we changed from Eclipse into Android Studio,
where now, we were building in
richer capabilities than we could at the time. Art came out. It was off by default
in KitKat, and it was the only runtime in Lollipop. This is huge, as you'll see
in some of our recommendations there, because it
really has changed, over time, the way we
look at the way you should write your code. Prior Dalvik information
does not necessarily apply in an Art world. Recycler view was released. Important because it was
a better version of List View with more flexibility. But also, we started
releasing components in the support
library disconnected from platform
releases, which means you could use these
new capabilities in your applications
across all the releases that you cared about. A little while later,
we had Constraint Layout built into Android Studio-- a richer way of actually
designing your APIs, as opposed to the rich way of
typing XML directly. Kotlin-- I think that
came out last year. I don't know. Some IO conference or something. Architecture Components--
these were announced last year. 1.0 in the fall. New way of doing
things, where we are trying to solve,
or at least help with, a lot of complex
problems with Android, and taking feedback
from the community and iterating on that to
create developer APIs that make things easier for you. That is the whole goal. Studio Profilers,
a much richer way for actually figuring out what
the performance metrics are for your application. KTx, the extension
library that came out a couple of months
ago for Kotlin. And recently, the
Paging Library came out and went 1.0 just this week. So this is sort of a scope
of some of the things that have happened over time. I'm pretty sure there was more
going on between 2008 and 2013. I just can't
remember what it was. ROMAIN GUY: All right. We're going to start with tools. Here's a tool that you may know. How many of you have used
this tool, Hierarchy Viewer? Oh, that's pretty good. Not everyone. So that was our tool
called Hierarchy Viewer. It was part of the SDK. It was a stand
alone application. There was actually another
version before that one. That was the one that I
originally wrote in a weekend because I needed a debugging
tool to optimize the platform. And for some reason, we
started shipping it in the SDK. It wasn't the fastest tool. It wasn't the prettiest tool. Actually, this one was built
by someone who, funnily enough, was spending a lot of
time actually sleeping at their desk. That was very interesting. I never used that
technique before. It didn't quite work. So now, we replaced it
with something much better, called Layout Inspector. It's part of Android Studio. One of the nice benefits
is that you can open multiple inspections at once. It's a lot, lot faster. So if you haven't used
that tool, go use it. It's a very easy way to
analyze your hierarchy and debug various things
like embedding and margining, and even performance sometimes,
if you have too many views that overlap each other. Here's another one that's the
old way of profiling the code. That was called Trace View. So Trace View is a tool
that already existed when I joined the Android team
in 2007, so it's been around for quite a while. Here, we see it in
action inside of Eclipse. It used to be its
own stand alone tool. So one of the issues that
we had with Trace View is the original version was
an instrumented profiler, so there was a lot of overhead. It was running on every
method that was invoked. It was running in
interpreting mode. And so you couldn't
really trust the numbers. So when it said, this method
took three milliseconds, that wasn't true. The method actually was
a lot faster than that, and the only thing you could
do is compare the relative time between different methods. And even that was difficult
because if a method was invoking native code, the
native code was not affected. So any method
invoking native code was skewed because numbers
were just all so wrong. Over the years,
we added sampling profiling to this tool. But still, it was
very difficult to use. Only a few of us even
were using it internally because it wasn't that great. A few years later, thankfully,
we introduced Systrace. So the big benefit of
Systrace over Trace View is that it gives you
a comprehensive view of the entire system. Trace View tells
you how much time you're spending on every line
of code inside your application, basically. But sometimes,
performance issues come from somewhere
else in the system. Maybe you're
blocked on something that's in a different process. So Systrace gives you
that view that you needed. Before that, we were
completely in the blind. And now, we have
new profilers that have been introduced
in Android Studio. I think they're
part of 3.2 or 3.1. I don't really remember. But if you go to
the Profiler tab, you're going to see a
real time graph of the CPU usage of your application
and the memories [INAUDIBLE] of your application. And if you double-click
on the CPU graph, you're going to
get to that view. It looks very similar
to Trace View. Again, it's a lot
faster, and it lets you do native code profiling,
instrumented profiling, sampling profiling,
and even Systrace. So this is the tool that you
should be using from now on, and this is what these
graphs look like. So we have, now, I
believe, four graphs. We have the CPU one, the
memory one, the network one, and the energy one. I've never used the
network one because I'm not sure what servers
are for, but I'm sure you guys
understand that and you will make good use of it. And that's what
it looks like when you enter the CPU profiler. So you get a flame graph. You have different ways
of analyzing the data. The one I like is
the flame graph. It's going to colorize
all the function calls with different
colors, depending on how much time they take. So anything that shows in
red shades or dark orange are the bottlenecks
inside your application. So a very easy way to drill
down inside your application and identify the bottlenecks. This is the native profiler. It's available starting
on Android 8.0, so you need Oreo or higher
to be able to run it. And I mentioned briefly
the new memory profiler, so to do memory
tracking, we used to use this tool called DDMS. Again, it was a
stand alone tool. It was built on the
eclipse platform. It was really difficult
to use because it was not part of the ID. At some point, we added
it back in the ID. And that was pretty
much the only good way you could see whether
or not you are locating memory in the wrong places. For instance, whether
you're doing drawing or whether you're doing
layout or touch handling. And now, it's part
of, again, Studio. So when you see this
graph that shows you, in real time, the
memory usage, you can even see the
different buckets. So it's going to tell you
how much memory you're using on your Java heap,
or how much native memory you're using, how much
graphics memory you're using. So you can pinpoint where
the problem is coming from. You can also create a
slice, as you see on screen. It's going to show you all the
allocations during that time. You can see the stack traces,
you can fold the references. You don't have to dump the
edge profile, converted to using edge [INAUDIBLE]. You don't have to run jhat and
see these horrible-looking web UI that you used to have to use. It doesn't do everything
yet, so sometimes, you still have to go to jhat, but
it's a very good way to get started if
you have memory issues inside your application. Layout Design used
to be like this. It's Article Design. And it's interesting because
when Android came out, it was very hard to convince
everyone to move to XML. Remember, a lot of
angry developers really wanted to write
Java code to build the UI. And now, we've given you this. So this is the constraint
layout visual editor, and now we have a lot
of angry developers who would love to use only
XML, and not the visual tool. So I guess we have to
invent something new just as a decoy to make you
start using this one. CHET HAASE: I think
the only constant is that engineers will
be unhappy with whatever new option you give them. ROMAIN GUY: Especially
if they're French. And if you went to the
What's New in Tools talk, you've seen a sneak peek of
a new tool for motion layout to create animations
using constraint layout. Nicola and John are going
to show that again, I think, tomorrow or Thursday. So go find that talk. And so we want to make it clear
that this visual designer is only the beginning. There's so much more we can do. We haven't had time to
build everything yet. But this new motion layout
editor is the next step. And building animations with
visual feedback-- real time visual feedback-- is a
lot nicer than using XML. Runtime and language, Chet. CHET HAASE: Sure. So Dalvik-- ROMAIN GUY: Don't be so sad. CHET HAASE: Dalvik
was awesome for doing what it was designed
to do, which was it was optimized for space. When the G1 came out, it
had 192 megs, 48 of which-- ROMAIN GUY: Well, 64-- a small portion was accessible
for the applications. CHET HAASE: A very
small amount of memory was actually available
for applications to use, so Dalvik could
not, as a runtime, take up a bunch of memory
for itself or all the heap and where it needed
to store things. So that meant that as
devices got better, as memory got larger,
it didn't necessarily have the capabilities to
optimize in the wholesale way that we needed to. At some point, they
basically started from scratch on the Art
runtime that, as we said, came out in KitKat and
was default in Lollipop. But back in the Dalvik
days, we basically had recommendations
that came from that because of things
like allocations being really expensive. It had to walk the heap and
find a place to put this thing, and the heap got
fragmented over time, which meant that even if it
had a bunch of space there, it didn't necessarily have a
lot of contiguous space in which to find a place to
put that object. And then collections were
also really expensive. You ended up-- you would
allocate things over time, and then eventually, it is
going to run out of memory. And when it does that-- when you're in the
middle of an animation, you're on the UI
thread, and it says, I need to allocate
space for a bitmap-- can't find the space,
better run a GC. You're probably going to
lose two or three frames just because Dalvik needed to
actually collect all the items without references anymore. So some of the recommendations
that we had were basically avoid allocating things
whenever you can. That's certainly the way that we
live life inside the framework because we are your
inner loop, but we also recommended that application
developers do that. One of the recommendations
that I believe the community has
seen batted around was don't use enums, right? Because it turns out
an enum structure-- the class structure-- is a whole
lot bigger than an int object, right? And we use ints
all over the place because we try to minimize
the amount of memory we're taking up, and we also try to
minimize the amount of time we're creating a new
object, as opposed to passing primitive
types around. We also said that
primitive types are cool. Ints are cool, floats are cool. Capital I integer, not so cool. Also, what's not
cool is autoboxing. So when you're using
standard collection classes, if you have a bunch of
information stored in these primitive types and they're
being autoboxed in and out, or if you're using other
patterns and approaches that cause these things to
get created into objects, you would see, in the
tools that we had-- like allocation
tracker, at the time-- that you'd be
autoboxing and causing allocations along the fly. And then eventually,
GC kicks in, and you hate yourself
just a little bit more. So modern world,
we now have Art. It is optimized for performance. It was created from the ground
up not to optimize for memory, but to optimize for performance. And this is performance in
terms of method call stuff, but it's also optimized for
allocations and collections. Way faster allocations
and collections for a few different reasons. One of those is it has it
set aside for large objects. So instead of putting
everything in the same heap, and then having to find
space for large objects amidst all the tiny ones,
it puts all the bitmaps in a separate heap, all
the large objects, overall. It's way easier to find space
for those large objects, and then the small objects
go in the separate heap. Also, really cool,
it can defragment. Dalvik could not defragment,
so it would allocate over time, and eventually, there
wasn't enough space for that thing you needed. So you would get these
obscure error messages where it said that it couldn't
find a megabyte because there's only 48 megabytes free. Doesn't make a lot of
sense until you realize, well, it's probably that
the heap is fragmented and we can't really
do much about that. Now we can. In Art, it defragments the heap. In an earlier release, it would
defragment when the application was in the background. Now, it can actually
defragment when the application is in the foreground, as well. So way better. So the recommendations
that we have now are go ahead and allocate
when necessary. It's OK. In fact, if you use
enums, I don't care. Go ahead. [CHEERING] Apparently, you do care,
so I hope you enjoy them. We still, as a rule,
tend to not use them in a lot of framework
code and APIs. ROMAIN GUY: I use them. CHET HAASE: They are there
sometimes, but as I said, we are still the inner loop. So we tend to be way
more conservative than you necessarily need to
be in your application code. Use appropriate types. I still think primitive
types are really cool, but you know what? If you need to use a collection
with an object type, that's OK. But be aware that these phones
are still constrained devices. Memory may not be 48
or 64 megs available, but it is still being shared
with everything else being used, being run on that system. Also, batteries are
really important. It's important to
let that battery last as long as possible. So if you're constantly
doing things all the time-- if you're constantly generating
garbage and collecting it, sure, Art is a lot
faster at that. But Art still has to
do the work of actually allocating and collecting, and
all of that stuff uses power. So it's still good to remember
that the battery uses power and that maybe you should
be conservative on what you're trying to do. And also, like the framework,
be aware of the inner loop bottlenecks. Don't do things in
a tight loop that may cause performance problems. ROMAIN GUY: So when
Android was started, the team decided to go with
the Java programming language to create
applications, and there were many reasons for that. The main one was it was an
extremely popular language. There were millions
of developers who knew how to use this language. There were many
excellent and free tools. So it was really helpful
for the quick adoption of the Android platform. Over time, we have
been, sometimes, a little bit slow at adopting
new versions of the language. We recently started supporting
the Java programming language version 1.8. I think they are reaching 1.10. But it served us for many years. Last year, thankfully,
we announced full support for the Kotlin
programming language. How many of you are
using it right now? [CHEERING] All right. CHET HAASE: Keep them up. One, two, three, four. ROMAIN GUY: Almost everyone. CHET HAASE: It was
definitely more than five. ROMAIN GUY: We'll
keep a few slides. So we announced it
last year in 2017. We're working in close
collaboration with JetBrains. We're making sure that our
tools work well with Kotlin, and then make sure that we have
access to the features we need. Overall, we like
it because it makes code more enjoyable
to read and to write, and we spend so much time
reading and writing code that it does matter. So I have a few examples here. They're going to
be hard to read, but it's OK, because you all
know how to write Kotlin. Those examples are taken
from the Kotlin extensions, so I'm going to go over
them really quickly. I like named parameters. You don't have to create
multiple overloads of methods or builders all the time. You can inline functions,
which is really useful when you create extensions, or
even when you create graphics code, for instance. We saw that. Operators. You can overload operators. You should be careful with that. You can abuse this quite a
bit, and I've done this myself. Once, I created an in
fix operator called X, because it looks like the
cross-product for vectors. Don't do that. It's a terrible idea. I put it on GitHub because
it's a terrible idea. You can do destructuring
assignment. So when you have
a POJO, we create methods called component
one, two, three, et cetera. Then you can do
multiple assignments in one line of code. So this is an example,
again, from Android KTx where we destructure an integer. So you don't have to
do shifting and masking of bytes and integers. We have data classes. Very easy way to create all
those getters and two string and equals and hashcode. So you don't have to,
and you don't even have to type the shortcut to
tell IntelliJ to do it for you. That's the level
of laziness that we have reached with Kotlin. So that's fantastic. And finally, yes. I just wanted to call out some
of the things that, to me, make Kotlin so appealing,
is very smart design decisions they've
made in language. And one of them,
for instance, is when a lambda is the last
parameter of a function, they have this special
syntax that you can use. You don't have to
pass the lambda as a parameter to the function. You can just open
the curly braces and put your code right there. It looks and feels
a lot more natural. So one of the things we're doing
now when we're designing new APIs in the platform--
starting with Android P-- we make sure that our Java APIs
are full of these conventions. When we have a single
abstract method interface, we make sure that the parameter
that uses the interface goes at the end of
the list of parameters so that Kotlin
developers can benefit from this particular
feature in the language. And we're going to
do more and more of that in the support library
and all of our future APIs. So for those of you who
are not using Kotlin yet, a project can contain
both Kotlin and Java. You don't have to convert all
your application to Kotlin. The next class you add to your
application can be Kotlin, or you can convert
an existing class. We have a ton of lint checks. If there are things that
are missing, go tell Tor. It's going to write it
pretty much in front of you and commit it right away. It's kind of a machine when it
comes to writing lint checks. Check out the
Android extensions. Again, there's a
talk by Jake Wharton, I think, on Thursday
morning about it. It's going to talk about a
lot of interesting things. We also created the style guide. So those of you who are
still using our Java guide-- I mean, we didn't
really have one, but if you're following
our source code, you're probably prefixing
your fields with M. You're going to be happy to
know that we're not doing that anymore with Kotlin. First, because we
don't really like it, and also because
you can't really do it because of the property
syntax in Kotlin, anyway. We also have an
interoperability guide. So if you're going
to be writing code that is meant to be consumed
by both Java developers and Kotlin developers,
[INAUDIBLE] that you're writing Java
code or Kotlin code, we have guides for
you that explain how you should be
writing your APIs so they can be used in a natural
manner in both languages. And those are the guides that
we are following ourselves for our new APIs in the platform
and the support libraries. CHET HAASE: Let's
talk about APIs. First of all,
layouts in Android, there are a bunch
of them, but these are kind of the major ones that
people dealt with over time. First of all, there
was AbsoluteLayout. And it's so easy to
use, why wouldn't you? Then you'd just tell
the view exactly where you want it to be, right? LinearLayout, you can
just nest those things as deeply as you want to
and get exactly the UI you're looking for. FrameLayout, it's fine. If you squint at it, it's kind
of like an AbsoluteLayout. ROMAIN GUY: That's the best
thing we can say about it. It's fine. CHET HAASE:
GridLayout, turns out it's a little bit
complicated to use, but we can figure that out,
and it has a lot of flexibility there. And RelativeLayout, we've
heard that it's expensive. Is this something we
should be using or not? So the modern world. Here's how we think
about AbsoluteLayout. ROMAIN GUY: We just
want to make it clear. [LAUGHTER AND APPLAUSE] CHET HAASE: The only reason
that this is not deprecated is because there is
one important class the subclass is from-- ROMAIN GUY: No,
it is deprecated. It is deprecated. CHET HAASE: It is deprecated. OK. Well, we deprecated it,
and that's about as far as we can take it because web
view is in AbsoluteLayout. Sorry, don't use that. Hopefully, you're not. LinearLayout, it's actually
fine to still use, especially for simple cases. If you're deeply,
deeply nesting, then you're deeply,
deeply wrong, and there's a better solution. We'll get to it at the
bottom of the slide. FrameLayout, it's also
OK for simple use cases. You need to put that
one thing in there with appropriate
padding and margins. That's kind of what
it's there for. ROMAIN GUY: And the dirty
secret of FrameLayout is that it's an
AbsoluteLayout in this case. If you use margins
correctly, you basically have an AbsoluteLayout,
but don't do that. CHET HAASE: Don't do that. Don't do that. GridLayout-- it turns
out that it's really intended to be used with tools,
except the problem was we never actually wrote the tools. ROMAIN GUY: I think we forgot. CHET HAASE: Probably
not the best layout to use for your situation,
unless you already wrapped your head around it. OK. There may be better
solutions out there. RelativeLayout-- we believe
that ConstraintLayout is, in general, a better solution. I would think of it as a
subset of the capabilities of RelativeLayout. It has a lot of the
same capabilities of relative positioning
of children, with respect to each other. But it has way more
relative positioning to guidelines and some of the
new capabilities they've been working on in ConstraintLayout. ROMAIN GUY: The way I like to
describe it is ConstraintLayout is a RelativeLayout that works. CHET HAASE: And also,
the best thing about it is it's tightly
integrated with the tool. It was written in tandem
by the same people with the tool, which means
the design tool works really well with that layout,
as opposed to, well, they created the APIs, and the
tools sort of never caught up. That is not the case there. We mentioned 2.0. It's not 2.0 yet. I would say it's 2.0 soon. So keep an eye out for
what's coming up in 2.0. The talk by John
and Nicola this week will go over some of
that stuff, probably. Final thought on AbsoluteLayout. ROMAIN GUY: Just
to make it clear. So we have a class in
the UI toolkit called AdapterView, which is the base
class for a number of widgets. So ListView,
GridView, and Gallery. And they served us fine
for many, many years. They had a few issues. They were difficult to maintain. GridView, I think,
has not been used by pretty much any
app for quite a while, maybe for applications. Gallery is kind of like
a horizontal ListView, and I'm pretty sure it's been
deprecated for a long time. And we haven't certainly been
looking at it for a while. So I wouldn't use it
if I were you, anyway. Probably doesn't work. So here are some of the issues. So an AdapterView
has an adapter, and the adapter is interfaced
between your data set and the view itself. So one of the things you
can do in the adapter is notify the view of any
changes in the data set. The problem is that
you can only notify it of coarse-grained changes. All you can say is, hey,
something has changed. So absurdly enough,
in ListView, we have a lot of code that's trying
to figure out what has changed. Wouldn't it be nice
if you could tell us, because you probably know? Well, we built an API
where you cannot tell us. So that's kind of dumb. We also used to tell you to
follow this pattern, the View Holder. So the View Holder--
and it's one of those things where
I've seen a lot of people mad online about the View Holder
because it's a lot of product plates you have to write. It was actually
extremely important. I went back and I looked
at one of our old talks, and using View Holder
pattern would give you an extra 10 frames
per second when you were scrolling your
ListView on the T-Mobile G1. So it did matter a
lot way back then. It's not as necessary anymore. But because of RecyclerView,
it's part of the API, so you can now get
it for free, anyway. And finally, animations. Animations are possible
with AdapterView. So for instance, let's
say you have ListView and an item disappeared
from the data set. And you'd like the
item to fade away, and the rest of the item to
collapse and close the gap. You can do this with ListView. All you need to do is write
this little bit of code. Chet wrote a blog post about
it, I think, a few years ago. [LAUGHTER] CHET HAASE: That was one
of the ListView animations. We had a series of
videos showing you how to do different ones. ROMAIN GUY: This is
part of the code. You only need to understand
the future observer and transient state and measures
and notes and animations. It was rather difficult. So instead, now, we have the
RecyclerView, thankfully. So this is just a
dumb application. The first time I actually
used the RecyclerView was a couple of months ago. It was so much easier. That was really nice. I was able to create a different
version of the RecyclerView. The nice thing
about RecyclerView is that instead of having
multiple widgets that are effectively different
layouts for your data set, you can specify a layout
for a single RecyclerView. So this is the same exact code
with just different layout managers for the RecyclerView. CHET HAASE: I should point
out, too, that all of those were vertical, but
you could actually have a horizontal layout. For years, people asked us
how to do a horizontal-- ROMAIN GUY: Oh, it's easy. CHET HAASE: Horizontal ListView. ROMAIN GUY: You just set a
rotation on the ListView, and then you have to
intercept all the touch events and rotate them. And then there's a few
more APIs that you probably need to override because-- anyway. That was easy. CHET HAASE: Secret, though. The easiest way is to
simply rotate your phone 90 degrees, which has gotten
easier with some of the system UI improvements in
the latest release. ROMAIN GUY: And one of the nice
things about RecyclerView-- it does so many things
in much better ways. We have paging and
we have prefetching. The API is nicer. You can change
layout managers, you can write your own
layout manager. But also, animations,
they come for free. So the equivalent of the
code we just saw is this. And in particular, with
RecyclerView, what you get is fine-grained changes. So you can tell
us, if an item was removed, what item was removed. When an item was added,
what item was added. You can tell us about ranges
of items that have changed, or you can tell us that
everything has changed. This is much better
for you and for us. CHET HAASE: All right. Fragments. In the old days, we
heard that fragments were really complicated. And also, we would
fix this thing. So we didn't necessarily have
everything correct or have all the APIs that people
needed, so we would put in improvements,
and we would put that into the platform release. And then applications
could only use that with devices on that
platform release. And so the modern advice is
don't use the platform version. We have since ported
all of that code to make all of the fixes
in the support library, and we have now
deprecated fragments in the core platforms. So don't use them there. Use the support library, or now,
Jetpack version of fragments. We are putting more
goodness there. So use those, and
also, we are continuing to make improvements. There's a talk on
fragments this week-- ROMAIN GUY: Tomorrow morning. CHET HAASE: --by Adam
and Ian tomorrow. So please check that out to hear
more information about things that we are doing,
as well as ways to use fragments, which
should be a little bit easier. A major one of those is the
new navigation controller. So check that out. It sort of builds on fragments. It doesn't depend on them. There is no
dependency, but it does build on those capabilities
for creating and navigating between the screens
of your application. Activities are very closely
related to fragments. In the old days, basically,
Android applications consisted of
multiple activities. That was the application flow
for all Android applications. We expected developers to do
this, and developers did this. When you want to go from
one screen of your app to another one, you launch an
intent, you get a new window. There, you have some window
animation to get you there, and there you are. The new approach is use single
activities when you can. It turns out that's a much
richer experience for the user. Those window animations--
well, they're animating, but they're not doing
anything interesting. They're not doing anything
that helps the user transition from one state of
the application to another. Instead, it's basically
completely separate windows that are coming into view
when you could actually use single activity approaches
to retain the same Chrome around the application. Might as well have
the same action bar with the content switching
out from underneath it, or use richer
animations, which are possible with either the core
platform animations or fragment animations. So go ahead and use an activity. You may have situations
in your application where you have different entry
points, especially if you have a deep length that someone
may come into your application with. Then, it's appropriate to
have separate activities. That is the way to
expose that information. But otherwise, try to
use a single activity. Fragments are not necessary for
single activity applications, but they can help with
this a lot, especially with some of the recent
improvements there and the navigation
controller stuff, too. Architecture. So here was the old advice. A few years ago-- OK, only 2016. So basically two years ago,
Dianne Hackborn posted this on G+. We usually get this question
from application developers, where they will ask us what
application architecture they should use in
their application. And our answer is
always, we don't care. We are not you. We don't know how your
application works. We don't know the
best architecture for your application, so
please make your own decision. And then there is usually a
follow-up question of, yeah, I get that. But which architecture
should I use? So Dianne posted
this to basically say this once and for all. We do not care. The components that
we have in there-- the content providers, the
activities, the services-- these are system-level
components. They're not an
architecture around which you build your application. So please build the
one that's appropriate for your application. The new advice is,
actually, we're happy to provide you some
recommended architecture. Because it turns out that
people would at least like some common advice
that makes sense, and we believe that
we have that now. Specifically, with the
architecture components, we think that we
have an approach that makes a lot of sense. We have APIs that
are easy to use and you can build around those. We are not demanding
that you use this. Please use the architecture
that makes sense to you. But we do have a
core architecture that we believe should work. If you're starting
a new application, if you have new developers
on your team, it makes sense. One of the reasons
that we worked with Android
architecture components was to solve hard problems. One of the hardest problems
was Android lifecycle. And our answer was,
all you need to do is understand this
diagram and memorize it. And someone, externally,
did their own version of that diagram, which looks
like this, which is actually a lot easier to understand
if you look at it like this. So that's basically everything
you need to know and keep in your head at all times. So the problem would
be, you would basically create a bunch of
methods in your activity so that you could track
and manage lifecycle. You're handling creation
and starting and stopping and resuming and pausing, and
you're probably doing stuff in destroy, as well. You're probably doing
too much on Create. You're probably having
race conditions, as well as leaks in your start
and your stop, and you're probably doing
that in the pause and resume, as well. And you're not exactly sure why
you're overriding on destroy, but someone told you
you probably should. So we'll do that, as well. So in the meantime, you actually
only know the lifecycle state if you override those methods. We didn't give you
a way to query that. We know what it is, internally. We're just not letting
you in on the secret. So there is no API
for you to query, so you need to override
all those methods, and then you end up chucking
too much code in there. So too much logic basically
happening everywhere. The new approach is we have
an object called the Lifecycle Owner. You can ask for a
lifecycle object, and then you can
either query the state if you want to know what
state of lifecycle you're in, or you can set an
observer on it, and then you can get
callbacks into those methods. This allows you to abstract
it into a separate place so you're not basically bogging
down activity code with all this information. But you're putting
it where it makes sense in your application. Fortunately, we override--
we subclass lifecycle owner or implement that in both
fragment and AppCompat activities. So in the support
library, please use these. Those are lifecycle owners. So basically, you can query
them to get the lifecycle, and then go from there. So we went from a model
where you would have activity with basically all of this
lifecycle-dependent logic in it to a model where the
activity can be much smaller, take that logic out, abstract
it into this other thing over there, set a
lifecycle observer on it, and get the callbacks you want. We have a similar problem
going on with views and data. We have an activity, and then
we have all this information about the views in there. And then we have the
data for the views, and we need to know
when the data changes, and we need to also
track the lifecycle so that we don't leak things or
call things at the wrong time. So we just end up having
too much stuff there. Well now, you had this
concept of a LiveData and a ViewModel
where you can put that stuff-- you can abstract
it out of the activity. So you can put all that
information out there, observe that stuff. So now, in the activity,
you should really have only information
about views and a reference to the ViewModel. And then put all of that
logic in the ViewModel. It's using LiveData objects. It's handling lifecycle on its
own, and you can observe it. Way better. Way less buggy. For data, our approach-- our argument to you
was you're on your own. We don't manage your data. Do whatever you want. And there are lots of
database solutions out there. We have SQLite in the platform. Go ahead and use it. Knock yourself out. Whatever. We don't want to get
into that business. The new approach is we actually
do offer something for data. It builds on top of
SQLite, but it actually offers build time verification,
so you're not just sending these queries down and
then getting errors at runtime. But you can see this problem
at build time and integration with the LiveData stuff
that we saw earlier, or you can be on your
own if you want to. We're not trying to take
over your database solution. We're simply offering a
better local persistent story than we had previously,
to make it easier for you. The overall diagram
looks like this. The only new element here
is this idea of repository. It's a pattern for
basically abstracting for where the data comes from. So if it comes
from local or web, it shouldn't matter to the
rest of the people that are querying it. So it's kind of nice to
have an abstraction there. Data paging. So we had this thing
called CursorAdapter. It had some good
elements about it. It did have support
for a database cursor. That's nice. But it was specific
to ListView, and it had, basically, other
problems with inefficiencies-- paging sizes, stuff like that. We had AsyncListUtil,
which was more useful, but also was really
inefficient for doing things like web transactions. So we have a new model
in modern Android. We have data paging. The Paging Library
when 1.0 this week, and there are good
things about it. So it works with RecyclerView. It handles fine-grained
data changes. It's much more efficient, uses
background threads very easily. You can observe changes, so
it's integrated with LiveData. But again, we're not forcing
this architecture on you. If you're using RxJava2,
you can integrate with that very easily, as well. And flexible data
fetching options, so you can specify
the window size and when you want
to get these things. There are, of course,
always trade-offs. I find that the bad
thing about data paging is that the name
is rather boring. ROMAIN GUY: Graphics. So when we started Android,
we only had OpenGL ES 1.0. We didn't even have shaders. We were doing everything
with software rendering. That was an issue
for several years. It was fast enough
for the early devices. It's only when we hit the
tablet form factor that it started to become an issue. We used to do a lot
of nine patches, and I'm sure some
of you have suffered through the creation
of the nine patches, or even worse, trying to
explain to your UX designer how to create them. Where do you put the black dots? Which side do they go? I still don't know, to this day. TextureView versus
SurfaceView, we touched on that in
our preview talk. Basically, there was
always this problem of do you use the less efficient
TextureView that can integrate better with the other views,
like ListView and animations, or do you use SurfaceView? And managing bitmaps was hard. A lot of you built applications,
and you were getting out of memory errors because you
were trying to create bitmaps and you have to do caching,
and this is difficult. And our answer was
basically, eh, c'est la vie. So now this. We have OpenGL 3.1 and 3.2. You have content
shaders, you have Vulcan if you want to do
low-level graphics rendering. We do hardware
acceleration everywhere. VectorDrawables have basically
replaced most of our drawables and bitmaps in applications. We have small applications. You don't have to support-- supporting multiple
densities is a lot easier. You don't need as many
batches as before. And something that
we're now doing is we're working with
you-- very often, application developers
turn to us for solutions. But when the
community-- that is, you-- have been building
amazing libraries that we think are the right answer, that's
the ones you should be using. So for instance, Glide
or Picasso or Lottie are excellent at what they do. If you want to manage
bitmaps or if you want to create crazy, complex
animation with Lottie, you should use those. We're not going to spend time
recreating something that already exists out
there and that we think is very good at what it does. So please go use
those libraries. Again, know this. You should probably
use SurfaceView, and not TextureView anymore. It has outlived its time. And finally, we used to tell
you to profile your code. We used to tell you to
avoid work whenever possible and to minimize
memory consumption. But now, we have better devices. We have lot of cores,
we have a lot of RAM. We have a better language. It's a better runtime. So instead, what you should be
doing is profiling your code and avoiding work whenever
possible, and also minimizing memory consumption. CHET HAASE: Because it
turns out that devices are still constrained. You need to keep that in mind. Battery life is critical
and bandwidth is precious, and all of these contribute
to user experience. So your user will thank
you if you are actually still being conservative
about these things and getting the best
performance for your application that's appropriate. We would like to thank you,
and there is a different way to say this. And I think we're done. Thank you. [APPLAUSE] [MUSIC PLAYING]