Single activity: Why, when, and how

[MUSIC PLAYING]

IAN LAKE: Hi, everyone.

Thanks for joining me.

My name is Ian Lake.

I am a developer on
the Android team.

And I work on quite a few
projects, but most notably

the Navigation architecture
component, as well as

Fragments, as well as
some of our new libraries,

like the AndroidX Activity
Artifact and Loaders.

And today, I wanted to talk
to you about Single Activity–

Why, When, and How, and
really try and share

some of the best practices
from the Android team

and from the architecture
component team on what actually

is going on in this world.

There’s been a lot of questions
way back from 2014, ’16,

and even here in 2018.

So we’re here today
to kind of talk

over all of those
wonderful things that

make up what are activities.

So activities are really a
component at the Android level.

So they’re at the same level
as content providers, broadcast

receivers, and services.

And they’re registered in
your Android manifests.

And really, they are the UI
facing pieces of your app.

So when the Android
framework goes

to start your application
from a launcher icon or an app

shortcut or what you see when
you’re doing multi window,

those are all activities.

So they really are kind of the
entry point into your app’s UI.

When the user goes
to launch your app,

they’re launching an activity.

And we had a very interesting
quote from Dianne Hackborn

back in 2016 that, “Once we’ve
gotten into this entry-point

to your UI, we
really don’t care how

you organize the flow inside.”

Now, this was 2016.

And I think it
was controversial,

I guess, in 2016.

Maybe we’ll just say it
had 77 comments on Google+.

So a lot of people were really
enthusiastic about this post.

But really, what does it mean?

Well, what I think it
means is that the framework

shouldn’t care.

The framework shouldn’t care
about your application’s

architecture.

It needs to provide the
hooks needed for the Android

framework to start
your application.

But you should probably
care about the architecture

of your app.

That’s why you’re
all here today.

And I love having you here.

So the biggest problem
is that you really

don’t know what an activity
is actually going to do.

So what’s the default
animation for an activity?

Well, it depends.

It depends on the
version of Android,

what manufacturer you’re on,
and even what themes the user

has selected.

So similarly, we had
property animations

that were added in API 11.

And they’re much superior
to view animations.

And the thing is that while
these new things become

possible on a new
version of Android,

they’re not always
applied to everything.

And things like activities,
they don’t support property

animations at all, even today.

And even if we were to add them
in the next version of Android,

maybe the letter
after P, we wouldn’t

be able to backport
them, because they’re

part of the framework.

So thinking about all these
things, it’s like, well, OK,

what should an
activity be used for?

Why do we even have activities?

They’re useful as this entry
point, but then beyond that,

you’re in your realm.

You’re in your realm of
what your app needs to do.

And you don’t
necessarily need to rely

on activities being the thing
that you have to work with.

So let’s take an example.

Here we have some
code like this.

We’re calling startActivity.

And we have to use
ActivityCompat,

because we want to do a
shared element transition.

So create our intent.

And then we say, oh, we want to
have this one element shared.

Well, what API does
this actually work on?

Well, it depends on what
you mean by “work,” right?

It technically
launches an activity.

That’s true, but it’s
only actually going

to do a shared element
transition on newer devices,

API 21-plus.

And really, how many compact
shims do we need in our life?

It technically works.

You’re saving some API
checks, but really this

isn’t the prettiest
code to look at.

And similarly, are there
any hidden gotchas?

If you are testing this on
the latest version of Android,

if you tested on an
older version of Android,

are you actually going to
get the same experience?

Well, in this example, I
actually ran into this.

And I was like, oh, well,
things are fading in and out.

And it’s like,
sure, I chose fade.

But it turns out you need to
exclude things like the status

bar and navigation bar.

Otherwise, they’ll flicker.

And I was like, OK,
well, that’s fun.

I wouldn’t have ever known
that unless I tried it once.

And I tried it on a whole
bunch of different devices.

And it turns out on some
devices, it’s totally fine.

On other devices, not so much.

So there’s a lot of
little hidden gotchas

here that you can’t actually
control or rely on in your app.

Another example where we
have multiple activities.

And really, each activity
is kind of its own component

in your app.

So if you have two
activities and you

want to share data between
them, well, there’s

not really a scope for that.

There is a scope
for that, but it’s

called your application scope.

It’s the same
scope that’s shared

by services and everything
else in your app.

But you really want kind of
a shared scope that’s just

within a couple of components.

So this is a structure
that Android provides,

but it’s maybe not the one
you actually want to use.

So what you actually want is
you want to build the layering

you actually need.

So in this case, we can
have multiple things,

multiple destinations
within an activity,

and share information across
each of these destinations

by using the activity scope as
an actually useful element now.

So for example, you could have
a shared view element or view

model that both
destinations talk to.

So one destination
could put data in,

and the other one could
observe changes to that data.

You don’t need to work
at the application scope

level for this to work.

So I mentioned this
word “destination.”

So what is the destination?

Well, really, it’s just
a subsection of your UI.

So for most
destinations, they’re

going to take over the
majority of your screen.

Like when you move
from one screen

to the next screen
in your app, it’s

going to change the vast
majority of your screen.

Maybe you have some global
navigation, like a bottom nav,

or maybe you have an
action bar at the top.

But the rest of this is
all in a destination.

So the subsection of your UI.

We have a word for
this called a fragment.

But a fragment is really
just one implementation

of this idea of having
separate destinations

for each screen in your app.

And really, this
fragment is serving

as kind of the view controller.

The thing that isn’t a
view itself, but something

that owns and changes those
views, which are really

more about display.

So really, the activity,
instead of owning

all of this business logic
and things like that,

is really as small as is
physically possible, and really

only working on the kind
that shared UI that’s

shared across all destinations.

However, thinking about this, if
we’re moving from this activity

world to a destination
world, we really

want to make that world
as easy as possible.

Otherwise, why would we move?

And we focused
kind of two things.

One was that global
UI kind of thing.

How can we make that part easy?

It’s something that
every app kind of

has the same kind of patterns.

And we really don’t want
that to be something that

takes a lot of effort to do.

Also, the navigating
between destinations,

that start ActivityCompat thing,
can we make that even easier?

So we started the Navigation
architecture component

and we introduced it to you all
in I/O this last year in 2018.

It is still in alpha right now.

And we’re looking to
fill out all the feature

gaps before taking
it to 1.0 here soon.

But really, what
this allows us to do

is take a super simple activity
like this, this set content

view.

We’ll set an action bar,
because that’s a thing, right?

And we want to make this smart.

We want to make this
useful, but we still

want it to fit on
this one code slide.

So some of this is we
need a NavController.

A NavController is really
the heart of Navigation.

It’s the thing that
knows everything

about how your app works
via a navigation graph.

  The components of Material Design

And we can get one–

we’re using Kotlin here,
Kotlin extensions–

and call findNavController.

And here we’re just giving it
the ID of a NavHostFragment.

The NavHostFragment is
basically that part of your UI

that’s going to change whenever
you change destinations.

We’ll also add an app
bar configuration.

This is what controls
the up action

and what needs to happen when
you move up from a destination.

And how do we hook that up?

Well, we have a nice one
liner that just says,

set up the action bar.

It gives it a
NavController and gives it

an app bar configuration.

Now, because we’re using
a drawer layout here

in our app bar
configuration, we also

want to open and shut the drawer
when you hit the Up button.

So we’ll call navigate up
in our support navigate up.

And we’ve set up our
whole action bar.

Now it changes titles as
our destinations change.

We’re good.

If we want to add
the navigation view

and make sure that we can click
on things in our side nav,

and then go to the right
place, that’s, again, one line.

We can do this all
because the NavController

knows about our
destinations in our app.

So then how do we actually
do navigate actions

if we’re not doing
fancy one liner stuff?

Well, we can get a NavController
from basically anywhere.

We’re in our activity.

We can use findNavController.

It’s even easier
from a fragment.

We can just call
findNavController.

And we’ve built the
Kotlin extension for this.

And similarly, even from a view.

Any view that’s created by any
fragment in your navigation

graph can just call
findNavController from a view.

So you have this reference to
it from basically anywhere.

And we really tried
to think like,

all right, well, if you have
arguments to something, how

do we make this nice?

So we built a Gradle plugin
called Safe Args, which

for every destination
in your graph,

such as this Main fragment,
we generate a directions

object, which has a nice simple
Show Profile method, which

gives you a directions object
with type safe arguments

that you defined in
your navigation graph,

and then you just call Navigate.

And that’s it.

We’ll take care of all of
the fragment transaction, all

of that sort of stuff for you.

So it makes it a lot easier.

But we can really go a lot
farther with navigation.

So has anyone ever built
an intent filter before,

deep linking, in your app?

Has anyone enjoyed
that experience?

Great.

One person enjoyed
that experience.

And really, you have to do
this, because this is what

the Android framework knows.

It knows, I can parse an intent
filter, and start an activity.

But oftentimes, that’s
not quite enough.

You need to go a
little bit farther.

So what we’ve done
in navigation is

for any one of your fragments,
any destination in your graph,

you can add a deep link.

It’s a simple one liner.

And you can even add
arguments right here.

And we’ll parse those
out even for things

like query parameters.

We’ll parse those
out, and give you them

as arguments to
your destination.

And then, because no one
likes writing intent filters,

we’ll also generate the
intent filters for you

by adding a navigation graph.

So this is something we actually
added to manifest merger

to kind of generate
that for you.

So all of this layering
helps us build nicer APIs.

But it also makes it easier
to test your application.

If you’re testing at
the activity level, all

of sudden that
means, well, how do I

test that start activity
actually did the right intent?

And we have to build
extra testing frameworks

on top of testing frameworks to
try and mock up these things.

If we’re moving towards more
of a single activity model

into the navigation
controller world,

we still want to test
all of those things.

We want that to be easy to test.

So rule number one
of testing things

at the destination
level is don’t

test the destination level.

It’s really the number
one thing with testing,

is making things
nice and separate,

and extracting some
of that business logic

out of a destination
and into something

you can test in isolation.

So an example, a view model
is a really nice place

to put some of your
business logic,

because you can test
it in isolation.

We have a view model
provider factory

for providing view models,
where you can just inject things

into your view model.

Test that totally
separate from your UI.

But that doesn’t mean
you don’t want to test

any of your UI stuff at all.

We have Espresso tests
for a reason, right?

We want to make sure
that all parts of our app

work well and are testable.

So how can we do this?

Last– this Monday, we released
Fragment 1.1, the first alpha.

And with this came
a new artifact

called fragment-testing,
which is

about like six years overdue.

And it’s really around being
able to test your AndroidX

fragments in isolation,
separate from an activity,

separate from everything else.

But being able to test and
verify that that fragment

is doing the right thing.

So super useful for things like
Espresso tests, where you do

want to test that logic.

Your business logic, separate
object, but your UI logic,

what happens when you
click that button,

is still something that we
want to verify is correct.

Now, the nice part about this–
it’s called FragmentScenario–

it’s actually built
on a different class

called ActivityScenario, which
is part of the AndroidX testing

team.

And actually, the
testing team was

instrumental in getting
FragmentScenario out there.

But the best part about
this whole scenario

is that it works both on
instrumentation tests, tests

on your actual device,
and on Robolectric.

So you’ve got one test framework
that works on both of these.

So a really exciting
opportunity,

and something that now you
can test with fragments.

So what does this look like?

So let’s say we want to
test our profile fragment.

We did our directions thing.

We’re passing in a
fake user ID here.

And we call
launchFragmentInContainer.

That’s it.

This one line has both created
an empty hosting activity,

added the fragment to it, and
waited for it to be resumed.

And now it’s ready.

You can now use this fragment.

So if you want to
call onFragment,

and run some code on your
fragment, and say, well,

is the fragment in
the right state?

Great.

You can do that.

Here, we’re just going to
check to see if our args are

what we think they are.

We’ve passed in a user ID.

We can use the other half of
safe args using the args class,

another generated class,
and just say like,

well, is the args
user ID actually

equal to the user
ID we passed in?

Did we not mess up on all
of that sort of stuff?

But you can see you
can run any logic,

any method on your
fragment right from here.

Or we just run an Espresso test.

You say, is the user
name actually equal

to the user ID we passed in?

When we click the
Subscribe button,

does it actually change
the text to subscribed?

Does it do its thing?

We can do this with
just that one line

of launchFragmentInContainer.

For Java users, it’ll be
FragmentScenario [? launch ?]

in container.

We obviously make that a
little bit nicer for you guys.

But you don’t test a
fragment in isolation,

because fragments do
talk to other fragments.

And like, I work on navigation.

So there’s that other
bit of testing of,

how can we test the links
between different destinations,

between different fragments?

And really, the nice
part here that we have,

because we’re using these
higher level components and not

something like activity, is
that we have a mockable layer.

One of the things that we found
when building navigation is

that most companies, once
they got to a certain point,

and they’re like, wow, we
should add some testing.

And they’re like, wow, we can’t
really test start activities.

So they built their
own navigator,

which just provides a layer
to mock out the start activity

calls.

Well, that layer
is handled for you.

It’s called NavController.

We test NavController.

So now what we can
do in our activities

is just mock out
that NavController

and confirm that,
yes, you’re calling

the right navigate calls.

So here we have our
profile fragment again.

  How to Film like a PRO with Android Smartphones

And now it’s
getting our user ID.

And really, what
we want to test is

this on viewSubscribers button.

So you can tell, we click this.

And like, oh, my god, it’s like
doing something complicated

in the fragment.

How are we going to test this?

Here, it’s calling Navigate.

How can we make sure
that this is actually

doing what we want it to do?

Well, it’s pretty easy.

We can do our scenario thing
just the same, launch fragment.

And now we can just mark
out our NavController.

And now you call onFragment.

And what we’re doing here
is actually just creating

our own NavController.

There’s no nav host here.

But we can just inject one.

This is actually
what NavHostFragment

is doing under the covers.

It’s calling setNavController
on a view, and saying,

here’s my NavController.

But now what we’ve done is from
this fragment’s point of view,

it has a navigation controller.

All those findNavController
calls that normally you’d

have to inject something in
to get your NavController,

now it just works.

They’re in there.

And now we can just
run Espresso tests,

and say, click on the
viewSubscribers button.

And the nice part is
that because we’re

using these directions class, we
can use them also in our tests.

And because they
implement equals,

we can just do a simple
verify, and say, verify,

did you actually
navigate to where

we think you’re navigating?

And even if there’s a lot
of parameters in there,

if there’s extras and
other options in there,

we can now just verify.

And this makes it so much easier
to test those interconnections

between each destination.

So nav control is kind
of a special case,

because we find a NavController.

So many other things aren’t
a service locator kind

of pattern.

It’s we need to inject
in those dependencies.

And this is another one of those
like “six years too late” kind

of a thing, but we’re
finally working on it.

So there’s a class in Android
P called AppComponentFactory,

which allows you to construct
activities, services,

broadcast receivers,
and services,

all via dependency injection.

You get a chance of
calling the constructor,

instead of the system
calling your constructor.

The same thing here
with fragments,

where now you can actually
do constructor injection

into fragments.

You no longer need to only
have a no-args constructor

to use fragments.

You can use a FragmentFactory
to instantiate your fragments

for you.

So this is really
useful also for cases

where your fragment
was like passing

your activity to something.

I know we probably still have
a template that does this.

We’ll fix that.

And there’s lot of
ways where really we

want to inject in all of
those external dependencies

so we can test
again in isolation.

And FragmentFactory works great
with our FragmentScenario.

So what does this look like?

We know how to
test a view model.

It’s just an object.

You instantiate it.

You do the thing.

And it has a real
method called Subscribe.

But really, we want
to test our fragment.

And our fragment has
an onSubscribe method

that calls viewModel.Subscribe
And it does its thing.

How do we get this viewModel?

Well, we can inject
the factory itself,

inject the viewModelFactory.

And here we’re using some of the
other new stuff in Fragment 1.1

that’s by viewModels, another
Kotlin property delegate that

does all that viewModel
providers of kind

of stuff for you.

But we now have a fragment that,
well, we’ve injected something,

but then we still need
to test like, OK, well,

did it actually call subscribe?

We’re back to the same situation
of building testable code.

We can build a
navigation activity.

This is what it’s going
to look like in real life.

We’re going to inject
our viewModelFactory.

And then because code is hard
and I wanted to write things

on slides, I built a
helper class called

Initializer FragmentFactory.

That basically just calls add
Initializer for each fragment.

And we call that method
to construct your fragment

rather than use the
default no-arg constructor.

So a little bit of magic.

There is a link here if
you want to check it out.

We’re looking at trying to
integrate this more deeply

into the actual library itself.

But once you’ve called
this FragmentFactory, now

whenever your activity creates
a profile fragment, instead

of using that
no-arg constructor,

it’s going to use
this constructor.

It’s going to pass in
our viewModelFactory.

So our activity looks fine.

But our test, how
does that look?

Well, we create a mock
of our profile viewModel.

And then we can set
up a factory for it.

And then, again, kind of
use a FragmentFactory here

that, again, does the
same type of thing

where we’re passing in
our mock viewModelFactory.

And then our scenario
looks almost the same.

We just add it in and add
instead of just the arguments,

also the FragmentFactory.

Great.

Now we can do our
same thing on view.

Perform the click.

And then verify that, yes,
our mocked out viewModel

did the subscribe call.

So now we have a testable
fragment, a testable viewModel.

And we’ve injected all of the
dependencies into our fragment.

We actually have
a testable thing.

Now, we are looking at some
improvements to this API,

because we want to
make this even easier.

So in this case, because we know
you’re constructing a profile

fragment, what we want
to change this into

is actually something
that looks like this,

where you can say launch, and
then give it a method saying,

oh, launch this fragment,
and specifically give it

the constructed out
instance of your fragment.

So you don’t have
to actually know

that, oh, it’s using a
FragmentFactory under the hood.

You can test just one
fragment just fine.

Now there are a few cases where
you might think, oh, man, maybe

I do need multiple activities.

And there’s got to be reasons
to use multiple activities

besides just momentum.

I understand a
lot of apps if you

have multiple
activities right now,

this isn’t actually
an easy sell.

So there are a few cases where
even today we do recommend

using multiple activities.

Not a lot, though.

So what I’d like to say
is you don’t actually

need multiple activities.

What you need are
multiple tasks.

So what are tasks?

Tasks are actually the thing
that users are actually

interacting with.

So a task is a
stack of activities.

And each task has a back stack.

So in your Overview menu here,
each one of these entries

isn’t just an activity.

It’s actually a
whole task stack.

So you’re only just seeing the
topmost activity of that stack.

So each element here is a stack.

When you’re doing split
screen multi window,

that’s two tasks side by side.

On Chrome OS
devices, things that

support floating multi window,
each one of these tasks

is a window.

So a one to one between
windows and tasks–

not activities and
windows, tasks and windows.

So launching a new task on
one of these Chrome OS devices

gives you a new window.

So your app, maybe it doesn’t
need multiple activities,

but maybe it wants
multiple windows.

So this is a case
where, yes, you

need to use activities
under the hood.

Each one of these tasks is
going to be a separate activity.

But you may not use some of the
other things, such as a stack

of activities, in one task.

So what does this
actually look like?

Well, a lot of
this is that there

are a lot of different
ways of saying new task.

Has anyone looked at all
those wonderful launch mode

flags and all that fun?

Yeah.

How many people that have
used it are still sane?

OK.

Well, I’ll say that there
were a lot of good flags

out there in Android 1.

They were great
back in Android 1.

Today, in 2018, they’re maybe
not the best thing to use.

What you actually want to
use is documentLaunchMode.

documentLaunchMode was
added actually an API 21.

So please if you’re thinking
about pre-API 21, first,

what are you doing?

And second, probably
try and steer away

from hacky solutions.

Maybe it’s just not
worth it for those users.

But try and avoid things like
launch mode flags and task

affinity and those
type of things,

because while the
framework does honor those,

it maybe doesn’t honor
them in the way you

want them to honor it.

They’re certainly a very
different kind of thing.

So what can you actually
do with documentLaunchMode?

Well, the biggest
thing is multitasking.

If you can have
multiple tasks, then you

can have multiple windows.

You can have multiple entries
in your Overview screen.

  Fix Mobdro Not Working Error, Network Connection Error on Windows PC

So the first way of really doing
multitasking is intoExisting.

Now, intoExisting
basically means

whenever I launch this activity,
that activity has its own task.

Every time you launch this
activity, it has its own task.

But if we already have
launched that task,

don’t create a second
and a third copy.

So this is really useful
for things like documents,

conversations,
things where someone

might want to
side-by-side compare

two different documents.

If they’re copy-pasting from
one document to the other,

they’re not going to
exit out of one doc,

open one, copy it, and
then open the other one,

and then copy it into there.

This is kind of taking that
multitasking model that

is Android, that is
that recent screen,

and making it so that your
app actually gets to use this.

Now, of course, the
intoExisting assumes

you have some notion
of uniqueness.

So it does assume that
from an intent filter

equals kind of point of view,
like if you’re using the data

URI on your activity, that
there is some sort of unique ID,

a conversation
ID, a document ID,

something to uniquely define
that task in and of itself.

Now one great example of
this that you can try out

on your phones is Google Docs.

So Google Docs,
when you open a doc,

it actually launches
it in a another task.

And if you have
multiple docs, you

can actually load
them up side by side

on a phone, two different
windows on a Chrome OS device.

And it just works.

Even though it’s one app,
it can have multiple windows

and really allow a different
level of multitasking

between different things.

So another big one is
creating new content.

So new content is
a little different,

because there’s not
really any unique ID.

But you still want that kind
of multitasking behavior

where you can reference
existing material while you’re

creating something new.

So the Always flag is very
similar to into existing,

but it just always
create something new.

Wow, it’s like
self-descriptive names.

We can do this, guys.

And it allows you to do
multiple things at once.

That’s great.

So one example of this is Gmail.

So Gmail actually
uses this kind of mode

when you create a new email.

So this allows you
to create a new email

and reference your existing
email at the same time.

Magic, right?

This is the equivalent on mobile
of when you do it on the web

and it pops up a
little mole that’s

separate from the other one.

You still need that other
material as reference even when

you’re creating something new.

Of course, on a
phone or on a tablet,

it looks slightly different.

The other case is
picture-in-picture.

Now, picture-in-picture actually
has two entirely separate modes

for how you want to
approach picture-in-picture.

One is using a separate task.

So this would be a
separate activity

just for your playback.

So this is really common
on Android TV devices.

For example, Google
Play Movies and TV

uses this approach so
that you can actually

put things into
picture-in-picture mode,

and then browse
through other movies.

So in this mode, it’s
very much that you

have a specific
Picture-In-Picture Mode

button in your UI.

The other mode is using just
a single task, one activity.

You actually don’t need
anything at all here.

And this is the approach the
things like Duo and Google Maps

use, where your whole
task is becoming

the picture-in-picture activity.

So when would you want to
choose one or the other?

And it’s really this
case where once I’m

in picture-in-picture mode, if
they were to click my Launcher

icon, what would happen?

Because the Launcher icon
always launches the default

task of your app.

So in Duo’s case,
where they only

have one task, when you launch
that Duo from your Launcher

icon, it’s just going to pop
open the picture-in-picture.

You go from a little
tiny picture-in-picture

to full screen, because
it doesn’t make sense

to have multiple conversations
going at the same time.

You’re never going to
replace one with the other.

You’re never going to continue
to reference something

even though something
is already going.

So that’s kind of the
differentiator here,

where do you want to be able to
browse and picture-in-picture

at the same time?

If you do want to
browse, then yes, you

are using the Android
framework, and therefore they

need to position
those separately,

separate tasks,
separate activities.

But that’s kind of it.

The one thing I didn’t mention
are things like Instant Apps.

Now, Instant Apps kind of
works at the activity level.

You call startActivity.

It downloads your
Instant App module.

But there’s actually some
really exciting things

that are being worked
on by the Play team.

I think there was a talk
here at Android Dev Summit.

But a lot of it is around the
instant experience for your app

bundle, making your whole
app instant, and also

dynamic feature modules.

These are really
interesting ways

of adding things
onto the thing that

don’t require a specific app
architecture to implement.

We can actually do
more things with this.

So for the instant
experience, it’s

adding this distribution
instant equals true.

Now, this means
that someone can try

your entire app, your
entire base module,

all at once, totally instant.

And this works really well
with things like app links.

So those deep links that I said
you can add to any destination,

you can also make them
into app links by adding

the autoVerify=”true”.

And that means you skip
the disambiguation.

And when someone launches
your deep link on the web,

they’re going to open up
your instant app experience.

They’re going to download that
whole base module for you,

and your whole navigation graph
is already there, ready to go.

But this doesn’t work if
your app is too large.

So you want to
dynamically deliver

things that are not used very
often or rather big things.

That’s what dynamic
feature modules

are all about, about being able
to download them on demand.

Now, the really interesting part
about dynamic feature modules

is that you’re adding classes.

You don’t need to
add activities.

You can add just destinations,
just a number of fragments.

So in this case, you can add
new destinations on demand.

Just because you’ve
built out an XML

file for your navigation
graph statically,

each one of these
dynamic feature modules

can also add their
own navigation graph.

So this means that we’re not
tied to separate activities.

We can now actually
still use one activity.

Now, there’s still
more to be done here,

both on the Play side and
on the Navigation side,

but we want to make this really
easy for developers to use.

So what we want to get to is
where you can add something

to your navigation graph
with just a feature tag,

just like you’d add a fragment
tag or something like that.

And when you navigate
to this destination,

that’s actually going to
do all of the downloading

and making your feature
module available from whatever

your split name is.

So that’s the world
we want to get into,

where you can use a single
activity, where you can use

a lot of the useful things, like
deep linking and navigation,

without necessarily contorting
your app architecture

around everything else.

So I’d really like to
end this with one note.

A lot of you have
existing apps that

have very different
kind of experiences.

And I’d like to say, do
what’s right for your app.

I think single
activity is great.

If I was writing a new
activity, it would also

be a single activity.

But I realize that
going to your PM

and being like, hey let’s
rip the whole app apart,

is sometimes a hard sell.

Some of them don’t
like your current app.

So maybe you’ll actually get
some, yeah, OK, go for it.

It really depends on
your own experience.

If you find yourself
contorting your own experience

and it’s not making sense
to you, don’t do it.

If something is
working, that’s good.

Keep it working.

But if you’re finding
you’re running into issues,

you’re having
inconsistent behavior,

or you want to do things
like share viewModels, maybe

that’s the time to
think about moving

towards a single
activity structure.

So thank you.

Q&A will be outside.

I really appreciate
you all coming.

[MUSIC PLAYING]

You cannot copy content of this page