An alternative to fragments: Say Hello to Mortar & Flow
This is a modal window.
The media could not be loaded, either because the server or network failed or because the format is not supported.
Formal Metadata
Title |
| |
Title of Series | ||
Number of Parts | 46 | |
Author | ||
License | CC Attribution 3.0 Unported: You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor. | |
Identifiers | 10.5446/47192 (DOI) | |
Publisher | ||
Release Date | ||
Language |
Content Metadata
Subject Area | ||
Genre | ||
Abstract |
|
droidcon Berlin 20158 / 46
5
7
10
13
16
18
20
21
23
26
31
34
35
36
41
42
45
00:00
Computer virusDataflowDataflowLibrary (computing)Square numberProjective planeExterior algebraGoodness of fitBitMobile WebSampling (statistics)Demo (music)Connectivity (graph theory)Lecture/Conference
00:58
Online helpMobile WebDataflowUniqueness quantificationView (database)Inheritance (object-oriented programming)Uniform resource locatorCartesian coordinate systemDataflowPoint (geometry)View (database)Computer animation
01:36
PiStandard deviationArchitectureProjective planeMultiplication signMobile appDataflow
02:06
Standard deviationArchitectureInheritance (object-oriented programming)Electronic mailing listRegular graphDataflowMobile appComputer architectureView (database)Endliche ModelltheorieLecture/Conference
02:30
Component-based software engineeringDatabase transactionOverhead (computing)Tablet computerData managementProgram flowchart
03:03
Touch typingSound effectDatabase transactionState of matterCodeLecture/Conference
03:39
State of matterView (database)LogicOverhead (computing)Database transactionSource codeData managementDataflowView (database)DampingLogicData managementDataflowSingle-precision floating-point formatProgram flowchart
04:20
ThumbnailGraph (mathematics)CodeBlogLibrary (computing)Drop (liquid)GradientSoftware developerPulse (signal processing)Sample (statistics)DataflowSoftware developerSquare numberRevision controlComputer animationLecture/Conference
04:46
TouchscreenFiber bundleDataflowStack (abstract data type)TouchscreenLibrary (computing)Presentation of a groupVariable (mathematics)DataflowOpen sourceCartesian coordinate systemState of matter2 (number)Square numberStack (abstract data type)Open setMessage passingLecture/Conference
05:59
Overlay-NetzInjektivitätFiber bundleSquare numberOverlay-NetzPresentation of a groupGraph (mathematics)Physical systemSocial classSign (mathematics)Context awarenessService (economics)Different (Kate Ryan album)RootCartesian coordinate systemHookingMereologyMobile appFiber bundleSystems engineeringDataflowArmTheory of relativityLecture/ConferenceComputer animation
07:28
Fiber bundleSocial classService (economics)Presentation of a groupView (database)File viewerFreewareLecture/Conference
08:06
Fiber bundleService (economics)View (database)DataflowInjektivitätAverageLogicGraph (mathematics)Module (mathematics)Object (grammar)Instance (computer science)TouchscreenPhysical systemHookingDataflowService (economics)Multiplication signFiber bundleInjektivitätView (database)LogicPresentation of a groupComputer animation
08:46
Multiplication signObject (grammar)Graph (mathematics)TouchscreenLecture/Conference
09:15
Integrated development environmentDegree (graph theory)View (database)DataflowPresentation of a groupEndliche ModelltheorieLecture/Conference
09:46
View (database)CountingOvalContext awarenessStreaming mediaInheritance (object-oriented programming)Set (mathematics)Module (mathematics)View (database)Frame problemTouchscreenCASE <Informatik>Module (mathematics)Structural loadMathematicsPresentation of a groupFiber bundleRotationState of matterLecture/ConferenceComputer animation
11:14
View (database)TouchscreenLinearizationLogicPresentation of a groupRight angleSocial classGraph (mathematics)Object (grammar)Lecture/Conference
11:39
Inheritance (object-oriented programming)Fluid staticsContext awarenessOvalModule (mathematics)View (database)Set (mathematics)TouchscreenAbstractionAttribute grammarCASE <Informatik>Service (economics)InjektivitätObject (grammar)Graph (mathematics)Presentation of a groupTouchscreenWindowTouch typingCodeEvent horizonVideo gameCycle (graph theory)Boilerplate (text)View (database)Computer animation
12:21
RootService (economics)Context awarenessView (database)Object (grammar)Graph (mathematics)Cartesian coordinate systemRoutingLecture/Conference
12:51
Modulo (jargon)RootCartesian coordinate systemModule (mathematics)TouchscreenObject (grammar)CASE <Informatik>Service (economics)Graph (mathematics)Physical systemLecture/Conference
13:21
RootService (economics)Context awarenessObject (grammar)CASE <Informatik>2 (number)Lecture/Conference
14:01
RootModule (mathematics)Service (economics)Context awarenessSound effectState of matterTouchscreenHierarchyGraph (mathematics)InformationLecture/ConferenceProgram flowchart
14:47
Object (grammar)RootInheritance (object-oriented programming)Graph (mathematics)Service (economics)Context awarenessInstance (computer science)RoutingPresentation of a groupCASE <Informatik>Cartesian coordinate systemGraph (mathematics)Service (economics)Multiplication signModule (mathematics)Physical systemObject (grammar)RootComputer animation
15:19
Library (computing)RootService (economics)Context awarenessModule (mathematics)Cartesian coordinate systemPresentation of a groupGroup actionGame controllerSet (mathematics)
15:48
Module (mathematics)RootDigital photographyRotationRepetitionTouchscreenCartesian coordinate systemDataflowMultiplication signState of matterPresentation of a groupProgram flowchart
16:50
Presentation of a groupTouchscreenRotationOverhead (computing)View (database)Lecture/Conference
17:16
RotationView (database)Service (economics)TouchscreenOvalInheritance (object-oriented programming)Structural loadStructural loadPresentation of a groupMultiplication signCountingTouchscreenLecture/Conference
17:46
RotationModule (mathematics)OvalCountingView (database)Service (economics)RepetitionPresentation of a groupDataflowService (economics)Cartesian coordinate systemCASE <Informatik>Fiber bundleProper map
18:11
TouchscreenStack (abstract data type)DataflowSingle-precision floating-point formatAdditionLogicDirection (geometry)BitDataflowLine (geometry)TouchscreenInstance (computer science)Single-precision floating-point formatSet (mathematics)CASE <Informatik>Cartesian coordinate systemFunctional (mathematics)Lecture/Conference
19:59
DataflowRow (database)Group actionCuboidSquare numberTouchscreenSampling (statistics)Library (computing)Lecture/Conference
20:39
DataflowTouchscreenDefault (computer science)ImplementationCuboidTraverse (surveying)Group actionMetropolitan area networkComputer animation
21:04
RotationBit error rateGroup actionRegular graph
21:31
Direction (geometry)DataflowView (database)Convex hullOvalLetterpress printingBootingMaxima and minimaConic sectionCodeView (database)Group actionTouchscreenScaling (geometry)Social classRoundness (object)CASE <Informatik>FreewareMereologyGreatest elementComputer animation
22:55
Social classDataflowAnalog-to-digital converterState of matterDataflowSocial classGraph (mathematics)Object (grammar)Event horizonFiber bundleSerial portComputer animation
23:43
OvalInstance (computer science)Wrapper (data mining)Exception handlingState of matterDataflowSoftware development kitKey (cryptography)State of matterDataflowCASE <Informatik>TouchscreenGreatest elementInstance (computer science)Sampling (statistics)Projective planeMobile appParsingLecture/Conference
24:51
DisintegrationTouchscreenState of matterPresentation of a groupVideo gameCASE <Informatik>Lecture/Conference
25:20
DisintegrationEvent horizonCASE <Informatik>ResultantFacebookScaling (geometry)Digital photographyTwitterLoginVideo gameCycle (graph theory)Data managementCartesian coordinate systemView (database)Event horizonGraph (mathematics)Presentation of a groupLink (knot theory)Lecture/Conference
26:21
Instance (computer science)Video gameCycle (graph theory)Presentation of a groupView (database)CASE <Informatik>Digital photographyLecture/Conference
26:54
DisintegrationDigital photographyOpen setOvalExecution unitFluid staticsAbstractionoutputStructural loadResultantElectronic visual displayPresentation of a groupVideo gameCycle (graph theory)View (database)RootSocial classCASE <Informatik>Cartesian coordinate systemComputer animation
27:52
Presentation of a groupResultantMedical imagingSlide ruleElectronic data processingProcess (computing)Lecture/Conference
28:15
InjektivitätUniqueness quantificationFlow separationModule (mathematics)RootData managementCASE <Informatik>Set (mathematics)InjektivitätInstance (computer science)Lecture/Conference
28:40
Content (media)Library (computing)Run time (program lifecycle phase)OvalInheritance (object-oriented programming)Module (mathematics)Fluid staticsSet (mathematics)Cartesian coordinate systemPresentation of a groupRootModule (mathematics)Right angleDataflowLecture/ConferenceComputer animation
29:30
DataflowArchitectureView (database)LogicExecution unitView (database)DataflowPresentation of a groupEndliche ModelltheorieLogicComputer animationLecture/Conference
30:01
Object (grammar)Point (geometry)DataflowGraph (mathematics)Cartesian coordinate systemLogicService (economics)Flow separationLecture/Conference
30:34
Sampling (statistics)Prisoner's dilemmaMobile appDataflowCodePoint (geometry)Cartesian coordinate systemLibrary (computing)Set (mathematics)Projective planeSquare numberFrame problemTouchscreenVideo gameCycle (graph theory)Lecture/ConferenceComputer animation
31:18
TouchscreenLecture/Conference
Transcript: English(auto-generated)
00:06
Good morning. Or lunch, I guess, almost. I'm going to talk to you about alternative fragments today and in particular two libraries by Square, modern flow, and how I've been using them in a project for about a year now, and just kind of walk you through some of
00:25
the different aspects of the libraries, how you can get started with it, and I have a sample project that you can check out afterwards. So, yeah, my name is, first I'm going to go a bit background, like how I use it, why I got started with it, then some details about
00:42
the libraries, and the deep dive is just looking at the particular components, and then we'll look at a live demo afterwards. So, yeah, my name is Torben Priemke, I work for a company called Jelly Industries, we're in San Francisco. I joined the company about a year ago, and we had a Q&A application, mobile only, it was like a new spin on Yahoo
01:05
answers, and that application was rebuilt using modern flow, because its UI was quite unique and fluid, and it needed to be very performant, so we're using just regular views and needed something to actually manage the interactions, the back stack and things
01:26
like that. So at that point, modern flow was still very early on, but we gave it a shot and it worked quite well. Actually about a month after I started, we started working on Jelly to start on a new project, which at the time wasn't as complex from
01:45
the UI, but we discussed whether we wanted to switch back to just use fragments, which I had been using before, on several projects, but decided to stick with modern flow, and I believe in the long run, that's been really paid off, more to that in a minute, but
02:06
yeah, the app uses just a lot of like regular screens with list and recycler views, but mainly, I mean, I think the benefit from modern flow is they're very clean in architecture, model view presenter. So some of the background, like the activities
02:26
and fragments, and when fragments became very popular about 2012, people started converting the activities to fragments to get some performance boost there. They were initially
02:42
intended to be used for master and detail layouts for tablets and make that easier, but also turn out that you can just use fragments within fragments and use the fragment manager to really manage those transactions and get a performance boost there, since
03:01
you're avoiding the overhead of the activities creation. So yeah, use a single activity and cache your fragments, but then you run into a few problems occasionally. On resume or on attach fragment, your fragments might not be in the right order as you've
03:22
seen them before, especially if you use only like height and show to not replace them and get the caching effect. As you want to do some transactions, you might run into illegal states, and a lot of the code becomes very defensive, and also a lot of the logic,
03:43
business logic and view logic is all clotted together. So if you don't want to use fragments anymore, I think there's a solution, it's modern flow, you have a single activity, that's how I built super, it has one activity, and just plenty of views inside of them,
04:04
and you know, you need a back stack management to do that yourself or to start from scratch. I know it isn't too hard, but if there's already another solution out there, why not try it?
04:21
So flow, it's available on GitHub, it was developed by Square, it's still a very active development, very recently, maybe about a month ago, some more stable and new APIs came out, also bad for people who were already using it, because it kind of broke things, and now
04:40
it takes quite an effort to actually update to the latest version. So what does flow do? It provides a way to define the screens and handles the navigation between them, it describes the screen, so each screen has a screen and a presenter inside that comes
05:03
from Mortar, that's the second library. The screen can also have things like a particular state, for example, you're passing in some variables for that screen that you want to pass to your presenter, those are attached to the screen, and also handled during the
05:25
piston state of the screen, so you can really store information along with the screen itself in the back stack. It handles the history and the persisting, and similar to nesting
05:41
different fragments to maybe encapsulate or compose flow, you can do the same thing with flow, it's open source, so if there's something that you're missing, but you need for your application, you can always build it yourself, that's how we kind of went about with the nested flows. Mortar is the second piece of it, also from Square on GitHub,
06:08
it kind of provides an overlay on the application lifecycle and shields a lot of it from your presenter, but it provides access to things like a bundler service, so any of your classes
06:25
can now store things in the persistence bundle, and it also works very nicely with a dagger. In order to make daggers or these different services available throughout the application,
06:41
those are attached via the context through get system service, and you override get system service to actually hook in your particular mortarscopes. So Mortar, as I just mentioned, has mortarscopes, you start with a root scope, things that you want globally available,
07:03
goes to your activity scope, where you will expose your activity so you can later inject your activity to any of your presenters. I have an example for that in a minute. And the scopes can also be used so you can really separate different pieces within your application, let's say you have one part of the app that's authorized, but
07:24
if the user signs out, you want an authorized flow, you can use two different scopes in order to actually provide different dependencies. So yeah, the bundle service, that one is just so that the activities persistence bundle can be easily utilized in any class,
07:44
particularly the presenter, which is already built in, but anywhere else you need, you can inject it. And yeah, it provides the view presenter, or presenter, that within your screens, your presenter always extends the view presenter, so you get all the persistent
08:06
state for free. As I mentioned here, we're doing the safe method. So now when we look at combining flow and Mortar together, they don't necessarily have to be used together, but Mortar without flow is not that useful, so both together really provide a nice package.
08:30
So again, Mortar leverages the get system service to provide access to persistence bundle as well as dependency injection and whatever else you wanted to hook in there.
08:42
The view presenters are now easily testable. Your logic is nicely separated. As far as the object graph, each particular screen extends it, so over time it builds up, but also as you navigate out of screens, those get torn down, so you're really keeping
09:03
a very thin object, or your object graph is very thin. And yeah, based on the MVP concept,
09:21
both your presenter and your view know by each other, talk to each other. When the view gets initially created, presenter is informed so that things like any data from the model can be passed back to the view and set up. And then lastly, flow provides back stack, as I mentioned, and provides the definition of the screens. So let's actually look at
09:47
how you would go about setting it up, setting your screens and your views up together. So here we have a pretty basic screen, could be a fragment, could be, you know, anything, but it's just views, in this case, I think of frame layout. If we look underneath, we can see
10:08
on the left side, the main screen. On top, we have definitions for the layout that's used, so that's automatically taken from the screen, as well as the module. So the module is where
10:23
you would add additional dependencies that you wanted your presenter to be able to be injected with. Below you can see the onload and unsafe methods. Onload is called after the view is created, so that anything that was injected into the presenter can now be passed to the view
10:43
and initialized. Unsafe, save any changes to the view, either in the persistence bundle or within your presenter itself. You also notice that the presenter is
11:03
singleton, so what that means is even when your activity is destroyed on rotation, your presenter actually persists, so any state that was within the presenter is still there after your activity and views get recreated.
11:22
On the right-hand side, we have the main view, main screen, main view. This one is, nothing much is in there. I abstracted a lot of logic. On the top, you see a class custom linear layout, and if we look at that, it actually handles first with the object graph service,
11:45
so that's the service that's used with a dagger for dependency injection to inject any dependencies. In this case, it was actually the main screen, the presenter, that gets injected into the view, and then on attached window and detached window,
12:07
the presenter is again informed about the life cycle events, so that you can either set up the screen or save anything. And since this is a lot of boilerplate code, I abstracted it, and now, you know, your regular view looks pretty clean,
12:26
and here is mostly a click handlers using a butter knife. So let's take a look at more of the scopes and how they work. So everything starts with your route, and you usually set that up within the application itself. When you set it up,
12:48
you can start with an object, see on the other screen, with the object graph service, so that's the first one you set up together with your module, and in this case, it would be your
13:03
application module. I think I'm showing it in a minute. And then that new motor scope is being used within the get system service method, so that when a particular service is requested, it can be interfered, and if it matches the particular motor scope, that one is returned,
13:28
so that any, like in the case of the object, I'll just show an example in a second.
13:52
And the second piece is that the scopes can be extended, earlier I mentioned about the off and on off, but I also use extended scopes or extended scopes for a particular thing such as
14:06
wizards, so we see that here, where from the activity scope, I go usually down to the main screen scope, when that one is shown, but in order, before I go to wizard, I inject another scope that contains information about the visit state, this way this particular state can be
14:28
injected on all the different screens, so from the wizard scope, we go to wizard screen 2, and again, because in the hierarchy of motor scopes is below, all the dependencies that are created
14:42
within the wizard scope can be easily injected and used, so here we see what I was mentioning earlier, how you set it up with a new application. The first time the sketch system service is called
15:00
and the root scope is now, we set it up, we initialize it with the object graph service and the root module, in this case it's the application module, which also gets passed an instance of itself, so that later on the application can be injected in any of your presenters.
15:21
This is the application module, you can see it also includes other modules, via dagger for the action bar as well as settings, and then the module exposes the application, as I just mentioned, so you can use it in any of your presenters later on, or presenters,
15:45
other controllers, wherever you may need it. So here's the scope example with the wizard, and okay, so here you can see the wizard starting, and we're going from screen 1 to 2,
16:16
each time you go in between, we increment the counter, that's just some value I'm keeping
16:20
a state with, and as you can see when we're done and return back to the main screen, that wizard scope was removed, and the second time we go into the wizard, the wizard scope is added again and basically reset, so this way you can always just keep a clean state of any of those subflows within your application that may need
16:41
the same dependencies each time, but you want to only maintain them while within that particular flow. So as I mentioned earlier, the presenter is a singleton within that particular screen, and so because it's injected into dependency, injected into the
17:05
view, it's only created once, and so screen rotation is this way handled very nicely, in the sense that your presenter is actually not recreated, so no additional overhead there,
17:20
and so here we can see, we go from, here again we keep an encounter, that counter is simply within the screen, presenter singleton, and we have this one value in here on load count, that's just incremented each time we go through the onload method,
17:42
as you can see I don't actually save that, you could also add the initial additional saving into the, with the bundle service, into the persistence bundle, mainly for your application actually getting paused, in that case obviously the presenter is torn down as well, and so you
18:04
need to have the setup, so that the screens, the screen on in the flows back stack can be saved properly. So next up, flow navigation, it's actually pretty simple, there aren't that many
18:22
methods anymore, it used to be a bit more complex, but they cleaned this up in the latest release, so there's really only a set method, and a set history, and a go back, the set method, so it is the first line, set new setting screen, it behaves differently depending on whether that screen is already somewhere on your back stack
18:42
or not, if it's not in a back stack, it will be added to the top and displayed, if it's already on the back stack, all the screens above it will be removed, and the new instance or the previous instance will be shown, so it kind of goes backwards,
19:02
in that case, otherwise forward, so if it's not there forward, otherwise backwards, set history, you can just start with a clean slate, and initialize with a few screens, if you want to prep, your application is starting up, and you're going immediately
19:21
to a detail of maybe a post, but you also want the feed below it, so you can initialize the history, and with the main screen, or maybe with the feed first, and then with the detail afterwards, so your user will first see the detail, but on back press, you see the feed,
19:45
history at single, it's just a helper, so you don't have to go through the builder, and go back is a simple back functionality, if you trigger it like from not within the back button,
20:02
or the action, the toolbar, so if you have anything else that causes a back navigation, you can call it directly on flow, since we covered the navigation, doing that navigation,
20:22
you also want some kind of screen transitions, that's something that doesn't come out of the box with flow, but in squares sample library, they have a simple path container, the last item actually implemented that has some sliding navigation, but yeah, it doesn't come with
20:43
anything out of the box, which also makes it very nicely extensible, so if you want some flying transitions, you can build those, as I mentioned there, the path container perform traversal method needs to be implemented, and that's what the simple path container does,
21:01
so you can use that as a good starting point, and as an example here, we have a scaling transition, and the sliding one, so it works just like regular fragment or
21:28
activity animations, and so it's going to take a quick look here at the perform traversal method, there's a lot of code, so I don't want to go through everything,
21:42
mainly the new view gets created, and based on whether there was anything before, we don't have to do an animation or transition, otherwise we'll do the animation, the thing to keep in mind if you do your own animation is that you actually need to destroy
22:07
the old path or the old view after the animation is done, as there might still be some callbacks while the animation is happening, so that's the part all the way on the bottom of the screen here where the view actually has to be removed and then destroyed once the animation is completed,
22:26
and within the perform traversal or within the path containers extended class, you also have a run animation method in this case, which here I just implemented those two scale and sliding
22:45
animations, so yeah first one scale, second one sliding, pretty straightforward, yeah so as I mentioned flow provides the back stack and therefore the history,
23:06
there's a class called flow delegate that has to be implemented within your activity in order to provide callbacks for all the lifecycle events, resume, pause, but also for safe instance, so that the history can be saved to the persistence bundle, one thing that's nice is that
23:26
you don't have to deal with passables in that sense or they're converted for you, but you can have a very simple, your screens can for example contain some complex objects
23:40
for which you have JSON serialization, so here you build your own possible, the state parser, and in this case there's a JSON one, so you provide this to the flow delegate and when your screens are persisted it goes through whichever parser you provide,
24:08
two methods need to be implemented in your parser, the wrap and unwrap, here within the flow delegate the small snippet that whenever your activity calls through to unsafe instance,
24:21
the history gets parcelized, and on the bottom here is one example that's actually from, not from my sample project, but from a regular project where we use a Jackson, so the annotations are a little different for JSON, but here you can see how within the screen I have states and those states then get actually serialized to JSON and also stored
24:45
with your history, so in this case your app may get paused but you want to persist the state, so the screen has it, you come back up, any of the previous values provided to the screen
25:01
are still there, so it's very nice and straightforward, so since it's so abstracted from the life cycle, the presenter doesn't have any hooks left to the activity, but there are cases when you do need that, when you do need to know about on pause, on resume,
25:25
or maybe on activity result, for example if you do Facebook login, Twitter login, or you use some external activity to do scaling of your photos, or even if you have your custom camera and you need to know when on pause is called in order to actually shut down the camera so that you don't
25:42
block any other applications from utilizing the camera, so you can you know do something very easy there and within your main activity check whichever is the topmost view container and pass those events down, life cycle events down, but I use a manager for that and it works quite
26:03
nice in that whenever there's a view presenter that does need these events, it automatically registers for any life cycle events and they can be processed within the presenter and there's no direct link between the activity and any of your presenters. So here, so the activity
26:25
has an instance of a life cycle owner, that life cycle owner has all the life cycle methods within the activity you want to call the life cycle owner, and then the life cycle view presenter also has the life cycle owner but registers for any callbacks.
26:44
So in the case of using the gallery picker to select some photos, the steps are you know you click on a button, a gallery opens and you actually need on result activity, I think so, and because I now have in my presenter the life cycle support,
27:09
I can actually receive the result from the picker and display it. So here I use a life cycle view presenter, normally there's just a view presenter class that comes with a mortar but in this case I extended it so I only have to actually
27:24
override the particular life cycle method that I need, so also you know inject the life cycle owner there as well as the activity, that way you can actually call the intent to
27:41
or issue the intent to open the picker, and that was because earlier when you set up the different scopes you start from the root scope in your application, you add another scope within your activity that actually has a reference to your activity so it can be nicely injected within your presenter. And then on activity results here to actually get the data, process it and
28:09
update the nice image from the previous slide. Another thing because of the dependency injection and just the capabilities that mortar kind of brings,
28:29
settings usually maybe you would have like some kind of manager that you would have an instance to everywhere, but in this case actually I use annotations for settings and then I have this particular settings module where my settings are defined, hooked up with the
28:45
application root module and then these settings can be injected within each of your presenters easily. The example here is first the annotation for user preferred name on the top,
29:03
on the bottom left you see the settings module where we actually provide or create the provides method within the dagger module and then on the right here in the settings screen the presenter gets directly injected that particular settings value and with get and
29:27
set you're nicely updated. So the takeaways I think from a modern flow that are that you can create a really nice and clean view presenter, model view presenter if you want to.
29:43
I am not very strict about always injecting, always injecting the model via the screens module simply because my data may come from other places but you can also you know model view presenter or just view presenter have both your view logic and your business logic nicely
30:02
separated. With the motor scopes and object graph service bundled with dagger you can really keep your object graph nice and small and always just scope to whatever you need at that particular point. For me big benefit are really the scopes for particular flows, compose flow,
30:26
onboarding flows where need very specific values that are really not relevant to the rest of the application. And that's it and yeah you can test your presenters. These are the resources
30:41
flow and motor and then the sample app will be up on on github and if there any questions happy to take those also can just go through the app that you guys can take a look at and see how it works. Some of the code within is actually leveraged from squares sample library as well
31:05
and then any of the things that I pointed out around life cycle settings, those custom frame layouts are all within this project as well it's kind of like my starting point for any new application. So we got that rotating screen but yeah you can start with questions I'm just
31:23
going to play with it. Okay thank you, it's all done.