[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. 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. 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. 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]
Got my first ever developer job in January as the only Android dev on the team and suggested we build the app like this. Haven't regretted since. Love the flow of things. Only problem is I wish we stuck with dagger for dependency injection.
So please. Since you guys already push fragment to be the major part of Android App. Add a mechanism to manage backpress in Fragments.
They finally admitted that the fragment is the controller. Vasiliy keeps getting acknowledged!
Hrmm their deeplink support is fancy enough that it makes me re-consider my stance, though I'm still not entirely sold on its customizability or lack thereof; I'll probably have to write a custom navigator eventually once it stops being beta.
[removed]
An 'argument' I have with myself every other week at work. It's late here but I'll def watch tomorrow morning. Thanks for posting.
They haven't acknowledged yet a big issue, in my opinion. They don't support nested fragments, ie. a navigator inside a fragment that is inside another navigator.
Since we can't do this, we only have two scopes available, activity and fragment. How can we share information between fragments without holding it in a viewmodel scoped to the single activity? This is very useful to represent multi step flows. Otherwise you have to pass the information along.
The Single Activity approach is really good, but it becomes a nightmare if you need to override
windowSoftInputMode
for specific fragment.You can set in on Attach/Detach fragment, however it doesn't work for Master-Details pattern and I still can't figure out how to handle it properly.