[MUSIC PLAYING]
MIKE CLERON: So hi.
I'm Mike Cleron.
I'm on the Android team.
I manage the system UI framework
and UI toolkit teams there.
We're going to be talking
today in a lot of detail
about some big changes to
how we recommend that you
build Android applications.
But before we go into
a lot of the details,
I thought would be helpful
to step back a bit,
and frame the discussion by
talking about where we came
from, and where we're going.
So let's do that.
So to start, Android
has always been based
on some strong principles.
Not surprisingly, those
were best expressed
by Dianne Hackborn.
She's the one who
actually architected
most of the Android framework.
She wrote a post about
this a few months back,
and I have some
excerpts from that here.
If you look at our
core primitives--
activity, broadcast receiver,
service content provider,
you might reasonably think that
those constitute an application
framework.
But that's not the right
way to think about it.
These classes are
actually contracts
between the application
and the operating system.
They represent the minimal
amount of information
necessary so that the OS knows
what's going on inside your app
so we can manage it properly.
So as an example, if your app
is running in the background,
but is also exposing data
to another application
through a content provider,
the OS needs to know that.
And we need to know that so we
don't accidentally kill you.
The content provider is a
mechanism that tells us that
so that we can keep you alive.
So we think of
these core classes
as really being like the
fundamental laws of physics
for Android, hence
the illustration.
That is the cover
of the manuscript
where Isaac Newton
first presented
the basic laws of motion.
Now, fundamental laws
are a good thing.
I use a shorthand when
talking about this.
I say, Android has good bones,
even though people look at me
funny after I say that.
But what I mean by
that is that Android
is based on a small,
stable, cohesive set
of core primitives.
And that allows a
common programming model
across a really
incredibly diverse range
of devices from wearables
to phones to tablets
to TVs to cars, and more.
This model also gives
application developers
the freedom to choose
whatever framework
they want inside
their application
for their internal framework.
So that means that we
on the Android team
don't have to get involved
in debates about whether MVC
is better than MVP, or whether
MVP is better than [? MVVBM. ?]
You guys can pick whatever
makes sense to you.
Now, that's a pretty good story
if you are in the operating
system business like, say, me.
But if you're in
the app development
business like, say,
all of you, that's
really only chapter
one of the story.
And the reason for
that is because
while strong fundamentals
and freedom of choice
are good things, we know that
in your day to day jobs--
and we know this because you
told us, you want more from us.
So I'm going to abuse
my analogy a bit here.
We can all appreciate the
simple elegance of Newton's laws
of motion, but if your job
is to land a Rover on Mars,
you don't want to
come to work each day
and start with only F equals
ma, and derive everything
from first principles.
So we've been talking to
developers, both inside
and outside of Google, and
taking a hard look at the app
development experience.
And we've realized
a couple of things.
First, there are
peaks and valleys.
Some aspects of app development
are better served by our APIs
than others.
For example, we think
RecyclerView is that the better
end of that spectrum.
So with RecyclerView, we didn't
say, hey, we give you events,
and you can draw stuff.
And in between you have a Turing
complete language, so good luck
with everything else.
On the other hand,
maybe Activity
and Fragment Lifecycles belong
down in that dark shadowy place
because there, I
think, too much of it
is indeed left as an
exercise for the reader.
And we want to fix that.
So as we thought about this,
we realized the good solution
has key properties.
First, we have to solve
the right problems.
This is going to be
a sustained effort--
like sustained
for us on Android.
But for the first cut,
we want to make sure
that we are going
after the problems
that every developer
faces, the things that
are hard to do right right now.
Again, app Lifecycles is
a really good example.
If you don't get that
right in your app,
nothing is going to
work on top of that.
And that's true for your
app, but that's also
true for the frameworks
we're trying to build.
We have to get that right
before we can do anything else.
Second, we have to
play well with others.
We know that you all have huge
investments in your existing
code bases, and we
can't create a model
where the first thing
we say to you is,
throw all that out
and start over.
So we're trying to create APIs
that you can adopt a little bit
at a time, and also
that interoperate well
with other libraries
or other frameworks.
Third, we want to
be more opinionated.
We're going to take a
stronger, clearer stance
on how to Android and
app the right way,
at least as we see it.
Now, this is all still optional.
And if you already have
something that works for you,
then great.
But developers are telling us
that they want more guidance
on how apps should be
built. And by the way,
we're not changing any of
the laws of physics here,
we're just layering some
higher level constructs on top.
Because after all, F is
going to equal ma whether you
believe it should or not.
Next, it needs to scale.
We want solutions that
are industrial strength,
and that will scale to the
real world requirements
of real world applications.
We don't want to build something
that's awesome for Hello World,
but then it's going to
collapse the first time it
bumps into the messy
complexities of reality.
And finally, reach.
For this problem,
for making it easier
for you to write Android
applications the right way--
what we think is
the right way, we
want to use libraries like
Support Lib wherever possible
rather than adding new
APIs to the platform,
because lets our solution
reach older versions of the OS
as well.
OK, so that's the background on
what we're trying to accomplish
and why we're here.
Now we'd like to introduce
Yigit, tool kit engineer
extraordinaire, and he's
going to walk you through what
we actually built. Thank you.
[APPLAUSE]
YIGIT BOYAR: All right.
Thanks, Frank.
Hello everybody.
So that was the background.
What are we shipping today?
The very first thing
we are shipping
is an architecture guide
on developer Android com.
Now for over years, you've
been asking us for our opinion.
Like how do we think that an
application should be built?
And this is that guide.
So we believe that
it's very good,
covers lots of
application cases.
But even if you
have an architecture
that you are comfortable
with, you can keep it.
But you can probably learn
something from this guide.
Second, we are shipping
a new set of libraries
that we call
architecture components.
These are more
fundamental components
where you can build
your application on top.
The first thing is Lifecycles.
So this is the biggest developer
complaint that we have.
Lifecycles are hard,
Lifecycles are hard.
And we said, OK, we
should solve this problem.
And the first level of this,
this new set of components.
Second one is
Lifecycle-aware observables,
which will go in detail
later, but this is basically
things that can do something
based on the Lifecycle.
Third, we are going to introduce
a lightweight ViewModel, which
is all of our effort
to take out that code
outside of your
Activities and Fragments,
and put it somewhere else
where you can easily test it.
Last but not least, we are
going to introduce a new object
mapping library for SQLite.
And all of this is available for
you today on Maven Google com.
[APPLAUSE]
Let's talk about Lifecycles.
So what is what's
hard about Lifecycles?
Why do we hear so many
complaints about that?
Let's go through an example.
Assume we have an
activity where we
want to show the location
of the device on the screen.
So you will try
something like this.
You create a LocationListener
on Create method,
you need to initialize
it with the context,
and you have a callback that
it calls whenever the location
changes, and you update the UI.
Now, if you have ever written
an Android application,
you know that this
code is never enough.
You also need to go ahead and
override onStart, and then
tell it to start, and override
onStop, and tell it to stop.
You always need to
do this babysitting
for these components.
But this is acceptable.
This a simple example,
this looks all right.
But then your product
manager comes and says,
oh, you know what?
We need to first check the
user settings before enable--
asking for a location.
Then your developer says, OK,
sure, that's an easy change.
I'm going to change this method
to first call this utility
method, which probably
makes a web service call
to check the user settings.
And then if the
user is enrolled,
then we want to start
the LocationListener.
Which looks like a
very simple change,
you will think this would
work, but let's look
at what happens in that
activity's Lifecycle.
So our activity was created.
We said, OK, run start check
if the user status is enrolled.
Then meanwhile, user wants
to rotate the device.
Which, rotation means
a configuration change,
which means Android is going
to recreate that activity.
So in onStop, we
knew about this,
and we said, OK,
location manager stop.
And then the new
activity came, it also
goes through the same thing.
Looks all right, except
do you remember this call
we made before?
That little change, and then
it decides to come back.
Hey, user is enrolled.
And then what we did?
We said, OK, then start.
And you realize the [INAUDIBLE]?
We called start after
calling on stop, which means
our activity will live forever.
We are going to observe
the location forever,
the battery will drain.
We will have sad users.
This is situation, right?
We want to get rid of this.
We want to put an end to this.
So we said, OK, we
need to acknowledge--
like as Mike mentioned,
we cannot change the laws,
but we can make it easier
to deal with these things.
So we decided to introduce
a new interface called
LifecycleOwner.
This is a thing
with a Lifecycle.
Is your activity, is
your fragment-- or maybe
you have your own UI framework,
whatever the container you have
there as a LifecycleOwner.
And we have these
LifecycleObservers,
which are the things that
care about the Lifecycle.
Like the
LocationListener we had,
it cares about the Lifecycle,
it wants to stop itself
if the Lifecycle is not active.
So we said, OK, we
will acknowledge this.
And we have a
LifecycleObservers.
And we'll go through the
code through our activity.
Now we make our activity extend
the LifecycleActivity class.
This is just a temporary
class until these components
reach 1.0.
Then everything
in Support Library
will implement this
LifecycleOwner interface.
Inside of our activity,
when we initialize
our LocationListener,
we are going to tell it,
this is the Lifecycle
you care about.
And that's all we will do.
But as it's the same, it
calls back the update UI.
So how can we change
our LocationListener
to take advantage
of this Lifecycle?
Oh, we do the same thing
for the UserStatus as well.
So there's some boilerplate
code here to get the fields.
It doesn't really
matter, but we have
this enabled method which gets
called if the user is enrolled.
Inside this enabled
method, now we
want to start
listening to location
only if the activity is started.
Now you can do this.
You can say, what is my current
state, which is amazing.
We didn't have
this API until now.
Well now you can.
So OK, that was a simple change.
But we also get
notified, what if we get
enrolled when the activity
was in back state,
and user comes back
to the activity.
Now we should actually
start the LocationManager.
For this, we want to
observe that Lifecycle.
To do that, we implement
this interface,
which allows us to
write these methods.
You can annotate
the methods saying
that, if ON_START
happens, call this method.
And the new components will
take care of calling you.
So if you are already
enabled, now you
start, and ON_STOP
you disconnect.
And last but not least, if
the activity is destroyed
there is nothing you want
to do with that activity
so you can unregister.
So now you might be asking
yourself, well, you just
moved those ON_START, ON_STOP
methods from the activity
into this Location Manager.
How come it is simpler?
It's simpler because
those methods
live in the right place.
It's the Location Manager which
cares about the Lifecycle.
So it should be able to
do it without the activity
babysitting itself.
I'm sure if you look
at your code today,
your activity ON_START, ON_STOP
methods are like, at least 20,
30 lines of code.
We want them to be
zero lines of code.
If we go back to
activity, I want
to point out something that--
look, in onCreate, we
initialized these components.
And that's all we did.
We didn't override, we
didn't ON_STOP, ON_START,
we don't override
any of those things
because the Location Manager
is a Lifecycle aware component
now.
So it's a new concept
we want to introduce.
A Lifecycle aware component in
a component can get a Lifecycle,
and do the right things.
It can take care of itself
so that your activity,
you can just initialize
it and forget about it.
You know that's not
going to leak you.
Now, of course, it was like
more of moving the complex
from activity to the
Location Manager,
and then it still needs
to deal with Lifecycle.
We said, OK, what do we want?
It's nice to be able to
do that, but we want more.
We want a very convenient
to handle this common case.
It's very common that your
activity or fragment, it
observes some data, and
whenever that data changes,
it wants to refresh itself.
It happens basically
almost every single UI.
And we want to share resources
across multiple fragments
or activities.
The location of the device
is the same from fragment
to fragment.
If you have two
fragments, why do you
need to create two listeners
to listen to the same location?
Hence, we created this
new LiveData clause.
Let's look at that.
So LiveData is a data holder,
it just holds some data.
It's like an observable, but
the tricky thing about LiveData
is that it is Lifecycle aware.
It understands about Lifecycles.
Because it understands
about Lifecycles,
it automatically
manages subscriptions.
So very similar to
the previous example,
if you are observing a LiveData,
you don't need to unsubscribe,
the right things will
happen in the right times.
So if that LocationListener
was a LiveData, and a singleton
because location
is singleton, we
could write the code like this--
get distance, start observing.
And when you observe, you
say, this is my Lifecycle.
This all you need to do.
Before on Android, if you were
observing something singleton
from an activity, everyone
will give minus two
to that code review.
Now you can do this.
This is safe,
nothing ever leaks.
So if you want to change
your LocationListener
to use this new API, we get
rid of the unnecessary things.
All we need is a
context to connect.
What we say, this is a LiveData,
this a LiveData of a location.
And we get these
two new methods.
One of two says
onActive, which means
you have an active observer.
And the other one
says onInactive,
which means you don't have
any observers that are active.
Now at this point, you're
probably asking yourself,
what is an active observer?
Well, we define
an active observer
as an observer that's in the
STARTED or RESUMED state, which
is like an activity user
is currently seeing.
So if you have an observer
in the back stack,
there's no reason to
put this inactive.
There's no reason to
update that activity
because user will never, ever
see what's going on there.
So inside our connect
method, all we need to do
is, whenever the system
Location Manager sends us
a new location, we call
setValue on ourselves.
Then the LiveData knows which
are the active observers,
and delivers the data
to those observers.
Or if one of the observers
was on the back stack
and then becomes
visible again, LiveData
takes care of sending the latest
data back to that observer.
And then we can make our
LocationListener singleton
because well, we don't
need multiple instances.
So if we look at LiveData, it
is a Lifecycle aware Observable.
It is very simple start
and stop semantics.
Doesn't matter how many
observers you have,
or what state they are, we merge
all of it into one Lifecycle.
And it doesn't have any
activities or fragments
inside it, but it works
with both of them.
And is also really used to
test LiveData because it's
kind of Android free.
And if you know about this
infamous FragmentTransaction
exception, we guarantee that
your observer will never,
ever be called in a state
where you cannot run
a FragmentTransaction.
So this is very, very
specifically designed
to work well with your
Activities and Fragments.
OK, let's think about
configuration changes.
Now, that example was easy
because location is global,
but most of the time,
the data belongs to a UI.
So if we had an activity
where we show a user profile,
and we implemented
a web service that
can return the data as a
LiveData which we can safely
observe without risking
leaking overactivity,
this all looks nice.
You will never
leak this activity,
it will work very well.
Except, what happens if the
user rotates to the device?
Let's look at the
LifeCycle graph again.
So activity is
created, it saves, OK.
Fetch the user.
And then while you
are fetching the user,
user decides, oh, I want
to rotate the phone.
And then that
activity is destroyed.
Luckily we don't leak
it, which is great.
But then the new
activity starts,
which makes this new call.
Now, this is OK, but not great.
What do we want?
We want to actually
retain that data, right?
We are already making that
request, why remake it?
So we want our graph
to look like this.
So if the new activity
comes, we should
be able to give it back the
same view model, which is
a new class called ViewModel.
So we are introducing
this new class
very specific to
this thing, where
you should put the data
inside your activities
into the ViewModel, and make
the activities data-free.
So if you want to
change this activity,
we create this new class, it
extends the VewModel class.
Whatever data we had inside
the activity, we move it there.
And in the ViewModel, all we do
is, inside the getUser method,
if this is the first goal,
get it from the web service.
Otherwise, return
to existing value.
Now, super simple.
And inside our activity, we
get rid of all that code.
We say, get the
ViewModelProviders.of this.
So each activity or a fragment
has a ViewModelProvider
that you can obtain, and
that ViewModelProvider knows
how to give you the ViewModel.
So when you call
get MyViewModel,
the very first time
you make this call,
we will give you a new instance.
When the rotated
activity comes back,
it's going to reconnect
to the same ViewModel.
And then the rest of
the code is the same.
[APPLAUSE]
So if you look at the
Lifecycle, this is how it looks.
This is what we wanted.
The new activity is
started, it reconnects.
And when the new
activity is finished,
like when we don't have anything
to do with that activity,
and then we go
and tell ViewModel
that it's not needed anymore.
This is actually the only
method in the ViewModel class.
So this is very simple.
So if we look at
Lifecycles, they
hold the data for the activity.
They survive
configuration changes.
They should never,
ever reference views
because they [INAUDIBLE]
leave the activities.
So you cannot reference
back to the activity.
That's why you use
things like LiveData,
Rx Java, or
datamining observables
to do that communication.
And this is what our
activity talks-- it always
talks to the ViewModel.
Now, another big
topic is persistence.
Now, we know that to write a
good, responsive Android app,
you need to save
the data on disk.
If you come to Android, there's
this three major APIs we have.
One of them is content
providers, which
is to talk between processes.
It really has nothing to do
with persistence, in reality.
The other one is
shared preferences,
which saves the data in XML.
So you can only put very
little data into that.
And the last one
is SQLite, which
is something we have been
shipping since Android 1.
So you know you
need to use SQLite
if you want to save big data.
And so you go into the
developer.android.com/ This is
the very first saving
your data slide.
This is so confusing.
This is very sad.
[LAUGHTER]
So is it-- OK, we want
to make this less sad.
We want to make it happy.
So we'll look at
the example, right?
So there's-- on top,
it tries to say,
I want to select these three
columns with this constraint,
and I want to order
them like this.
This actually really,
really simple SQL query,
but you need to
write all this code.
Plus, this code
doesn't even show where
you define all those constants.
So what do we really want?
We want to get rid of that
boilerplate-free code.
When you are writing Java,
if you make a typo in Java,
it doesn't compile right.
We want the same thing for SQL.
We still want to use SQLite,
because on every single Android
device it's a proven technology.
We know it works very well.
But we want the compile
time verification.
So we don't want the
boilerplate code,
we want to compile
time verification.
So we said, well-- we came up
with Room, which is an object
mapping library for SQLite.
[APPLAUSE]
So if you look at
this query, we said,
OK, let's move this query
inside the annotation.
We like annotations.
And we have this
feed object, which we
want to save in the database.
I want to put that query
inside an interface.
You want to create the FeedDao--
the Dao stands for
Data Access Object.
Usually in database, the best
practice to put your database
access into certain interfaces.
Then we just need to tell
the Room, this is a Dow.
Tell Room this is an entity.
And finally, we had a
database class which says,
I have these entities-- so
you have multiple entities,
and I have these data access
objects, as you saw them.
This is all you write.
Once you write that, you can
get an implementation of it
from Room.
It's very similar to how
you use Retrofit or Dagger--
you define the interfaces, we
provide the implementation.
Now, once we know
this is a Dow, we
can do these shortcut methods.
Like, insert these items, or
delete these items, or update--
a bunch of shortcut methods.
And you can press
multiple parameters.
As long as you can read
it and it makes sense,
Room will understand it.
But the most
important part of Room
is, it understands your SQL.
So the part-- all
those constants
I mentioned we defined to
get compile time guarantees,
Room actually gives
all of this for free.
So when Room sees
this query, says,
OK, you are receiving
these three columns
from this table where the
title looks like this keyword.
Where is this
keyword coming from?
Oh, it's coming from
the function parameters.
Makes sense.
And what does it want to return?
It wants to return
a list of feeds.
And then Room goes and checks.
Does the columns
returned match the object
the user wants to return?
And once they're equal, it says,
OK, I can generate this code.
You can have even
say, select star.
You don't need to list them.
Room really, really
understand your query.
You can even join 10
tables, it will still work.
But what if you made a typo?
Instead of saying feed
table you wrote feeds.
Now, if this happens,
Room is going to give you
an error at compile time.
So it goes out and
verifies your query
against the schema
you have defined,
and it tells you if
something is wrong.
[APPLAUSE]
But that's not the
only thing it does.
So if you said--
if your query is correct, you
want to fetch ID and title.
This said, well,
it's query, but you
want to return it as a string.
And then Room says, well, you
are returning two columns,
but you only have one string.
That doesn't make sense.
And it's going to give you
a compile time error again.
And there's a really nice
way to fix this in Room.
You can basically
create any Java class.
It doesn't need
to be annotating,
there's nothing special
about that Pojo,
and tell Room to return it.
As long as whatever
query it returns
matches what you
want it to return,
Room will write
the code for you.
And observability, which
is very important, right?
If you have a query
like this, now you're
showing lists of
feeds, you obviously
want to get notified
when the data changes.
And in Room, if you want to
do this, all you have to do
is tell it.
Tell it to return a LiveData,
and it will do it for you.
Because it knows your query,
it knows what things affect it.
So it can let you know
if that query changes.
And this is the part where all
these architectural components
work well together.
Room already knows
about LiveData.
So your ViewModel, all you would
write is-- from the data is,
call this query, and
this all it will do.
Whenever that data changes,
your UI will get a new update.
And it only happens
if the UI is visible.
Last but not least, Room
also supports RxJava 2.
[APPLAUSE]
OK, if we look at
Room in a nutshell,
it writes the
boilerplate code for you.
It has full SQLite support.
You can just write in
SQLite, there's no builders.
It verifies your
queries at compile time.
It incentivizes best
practices, which helps you
with testing migrations.
And it's also observable
out of the box.
OK, architecture,
our last topic today.
So where we started, right?
And now, you might
be asking yourselves,
what has changed
in 2017 that you
are talking about architecture?
Well, actually
nothing has changed.
We've been talking
about this topic a lot.
Adam Powell and I gave a
lot of talks on this topic.
There's even a talk from 2010
which I watch as a developer.
So this is a topic we have
been more clear about.
But what is missing was
a well-defined reference
architecture.
So it's what we
are shipping today.
If you go to
developer.android.com today
after the session,
there's a section
about how to architect
an Android application.
[APPLAUSE]
So by the way, this
is a reference guide.
This is not your religious book.
We believe this is a very good
way to write applications,
but you don't need to
follow it line by line.
So I'm going to briefly go
through this architecture,
but if you get
lost, don't worry.
We have all of this documented
on developer Android com
with sample applications.
So we think that
an application is
composed of four main things--
there's UI controllers, the
view models, a repository,
and the data sources.
So let's look at
these in detail.
UI controllers are
your activities,
fragments, custom views.
They have really simple tasks.
They observe the
fields of the ViewModel
and update themselves.
And they want more
responsibility.
Whenever user takes
an action on the UI,
they understand that action,
and call the ViewModel
to express whatever
the user wanted to do.
If you go to our view
model, view model
is the one which prepares
the data for the UI,
and holds onto it.
This is where the
data for the UI lives.
View model knows how
to get that data.
Usually it has LiveData.
If you are using Rx
Java, it is observable,
or datamining observables.
It survives
configuration changes.
That's why we put the
data into the view models.
And it is also the gateway.
You can also consider it
as, your UI controller only
ever talks to the
view model to reach
to the rest of the application.
And then what's the repository?
Now, the view model
serves as a data store
for your UI controller, right?
Repository saves
it as a data store
for all of your application.
So it's the complete
data model for the app,
and it provides this
data with simple APIs
to the rest of the application.
You can have a user repository
where you pass a user ID,
and it returns your
LiveData of users.
How it gets the data?
You don't care, it's
the repository's job.
So how does it do that?
It talks to the--
fetching, syncing,
looking at database,
or talking to your
retrofit back end.
It's the repository's job.
And last but not least,
we have our data sources,
like your REST API client.
You might be using Retrofit,
or you have SQLite storage.
You might be using Room,
or you might be using
GRAM, doesn't really matter.
Or you might be talking
to other content providers
from other processes.
These are things we
call data sources.
And we think that
all of these layers
can discover each
other to create
dependency checks
to the system which
we'll command using Dagger.
But we also realize that
understanding dependency
situation is not very trivial.
It's a more complex topic, and
sometimes might be an overkill.
And you could also
use a service locator
if you feel more
comfortable with it.
So let's go back to--
go through a concrete example.
Let's say we have a UI
that shows a user profile,
and we have the
data sources which--
we save it to database, we also
can get it from the network.
How do we connect
these two things?
Well, we said we first
need a user repository.
User repository knows it
should check the database.
It's not there,
make a web request.
Or meanwhile, also try
to run the database.
It doesn't matter
how it does it,
but it knows how to
create a LiveData
of a user or an
observable, doesn't matter.
And then we need the
ViewModel, right,
because the data for the
UI lives in the ViewModel.
So we create this
ProfileViewModel,
which talks to the repository
to get this information.
And then the actual
fragment gets the data
from the view model so that
if the fragment comes back,
the LiveData will be there
in the ProfileViewModel.
But if the fragment
disappears completely,
we will get rid
of the ViewModel,
and the data can be
garbage collected.
Now, all this
abstraction we made,
if you notice, every single
component only talks to the one
right below it, which is--
helps to scale your application.
It also has a
great side benefit,
which is called testing.
You're testing, right?
So let's say you
want to test your UI.
Now, people say UI
testing is hard.
UI testing is--
yes, it's harder.
But it's usually hard because
you put all of your code
into that activity.
Now, we said, put most
of it into the ViewModel,
and you know that UI only
talks to the ViewModel,
so you can get rid
of the other two.
You only need to create a fake
ViewModel to test your UI.
Testing your UI become super,
super easy with Espresso.
And we have a
sample app on GitHub
that you can check
out with [INAUDIBLE].
And the same thing as
well as for ViewModels.
If you want to
test the ViewModel,
you know it's only talks
to the repositories.
You replace it with a mock
respository, and it works.
And you can even
test your ViewModels
on your host machine, on JVM.
And last but not
least, you can test
the respository the same way.
You just mock the data sources.
You can easily test your
repositories as JUnit test.
Now, I know this has been
a lot of information.
We have two sessions tomorrow,
and also documentation.
But now I want to call
our product manager lUKAS
to talk about what to do next.
[APPLAUSE]
LUKAS BERGSTROM:
Like Yigit said,
we just covered a lot of ground.
And actually, we glossed
over a lot of detail
while we did that.
But luckily, you don't
have to remember everything
that you just heard.
We have a lot of material
for you to check out
at developer.android.com/arch.
And that link should start
working in 21 minutes.
We wanted to give
you guys a chance
to kind of blog and tweet
about this before anybody else.
So that's why we held it back.
So yeah, we made having
good documentation
and samples a priority from
the beginning of this project,
since providing good guidance is
really one of the major goals.
So you're going to find
in-depth documentation that's
written from the perspective
of an app developer.
You're going to find really
meaty sample apps that
show how to build a real app.
And just as an example of
how much work went into this,
we have a GitHub
browser sample app
that probably has better test
coverage than many real world
apps, written by that guy.
And of course, we have the
guide to app architecture,
which internally, we called the
Opinionated Guide for a while.
And we think that
label still applies.
But even if you're not
planning to use our recommended
architecture, we think people
should check out the guide.
It has principles that we think
apply to all apps on Android.
And you're probably asking
yourself, do I not--
what's the impact of
this going to be on me?
Am I going to have to change the
way that I'm doing everything?
You know, if you're
starting a new project,
or if you have an
existing app, but you
want to improve the
core architecture,
then yeah, we recommend
taking a look at this stuff.
It's still preview.
We won't be hitting
1.0 for a few months,
but we think it's definitely
ready for you guys
to check out, and
use in projects.
But if you're happy
with what you have,
you don't need to
rewrite your app.
So in the spirit of be
together, not the same,
we're not dictating what
everyone has to use.
If you're happy with your app
architecture, you can keep it.
If you're happy with
your existing ORM,
you don't have to use Room.
Architecture components are
designed to work well together,
but they do work
perfectly fine standalone.
And mixing and matching
applies not only
to architecture components,
but also third party libraries.
So-- I'm waiting for
this slide to come up.
So yeah, so you can
use what you have,
and to start to integrate
architecture components where
they make sense.
So for example, if you're
happy with Rx Java,
but you really like the
Lifecycle aware component stuff
that Yigit just showed, so that
you have these self-sufficient
components, you can use
LiveData together with Rx Java.
So you can get all the
power of Rx Java operators,
and now it's Lifecycle safe.
So kind of the best
of both worlds.
And we've got additional
integrations to come.
We're definitely looking at
a lot of stuff internally
that would be nice if
it were self-sufficient
and Lifecycle aware.
And if you're a
library developer,
we really recommend
checking out Lifecycles
and LifecycleObserver
because we think
there is a really bright
future, and a lot of potential
in making libraries and
components that are Lifecycle
aware by default.
But before you go
do that, we have a lot more
for you at I/O this year.
We have two more talks,
one on Lifecycles
that's even more in-depth than
what we just showed tomorrow
morning.
We have another one on
Room and Persistence,
and going a little
bit beyond Room
starting at 12:30 tomorrow.
And we'll have people who are
well-versed in architecture
components in the
sandbox for all of I/O.
And we also have codelabs,
which we're pretty happy with.
And there's more to come.
So we think we've just
scratched the surface of ways
that we can improve the
experience of using Android
Frameworks, and we're looking
at applying this approach
in other areas as well.
So some things
already in the works.
And we're also interested in
hearing from you on what else
you'd like to see.
So come by, talk to us, tell us
what you like, what you don't.
And stay tuned, because we're
really excited about the future
of Android development.
Thank you.
[APPLAUSE]
