We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

An alternative to fragments: Say Hello to Mortar & Flow

00:00

Formal Metadata

Title
An alternative to fragments: Say Hello to Mortar & Flow
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
Publisher
Release Date
Language

Content Metadata

Subject Area
Genre
Abstract
The introduction of fragments made it possible to split activities into smaller, more manageable components and allowed to build responsive UIs. Further taking advantage of the FragmentManager allowed hosting all fragments within a single activity. However fragments also caused headaches; ensuring that a transition is safe, magic fragment re-creation and ensuring the correct fragment is shown after an activity is re-created to name a few. In this talk, we will take a close look at two libraries: Mortar (with Dagger) and Flow. Leveraging these libraries allows creating well structured and cleanly separated components yielding reusable and testable user interfaces. Built as a layer on top of Dagger, Mortar provides scoped injection of components and provides lifecycle callbacks. These scoped subgraphs are only around while a screen that requires them is in scope thus keeping the memory footprint small. The separation of views and presenters fosters code that is easily testable. Flow provides the means to navigate between screens and manages the backstack. Flow can be freely extended to provide custom animations between screens since it is handling plain old views. The takeaways from this talk are that Mortar and Flow provide an excellent alternative to Fragments and utilizing them can help you build well architected applications with responsive UIs as well as being able to easily add unit tests for the business logic in the presenters.
18
Computer virusDataflowDataflowLibrary (computing)Square numberProjective planeExterior algebraGoodness of fitBitMobile WebSampling (statistics)Demo (music)Connectivity (graph theory)Lecture/Conference
Online helpMobile WebDataflowUniqueness quantificationView (database)Inheritance (object-oriented programming)Uniform resource locatorCartesian coordinate systemDataflowPoint (geometry)View (database)Computer animation
PiStandard deviationArchitectureProjective planeMultiplication signMobile appDataflow
Standard deviationArchitectureInheritance (object-oriented programming)Electronic mailing listRegular graphDataflowMobile appComputer architectureView (database)Endliche ModelltheorieLecture/Conference
Component-based software engineeringDatabase transactionOverhead (computing)Tablet computerData managementProgram flowchart
Touch typingSound effectDatabase transactionState of matterCodeLecture/Conference
State of matterView (database)LogicOverhead (computing)Database transactionSource codeData managementDataflowView (database)DampingLogicData managementDataflowSingle-precision floating-point formatProgram flowchart
ThumbnailGraph (mathematics)CodeBlogLibrary (computing)Drop (liquid)GradientSoftware developerPulse (signal processing)Sample (statistics)DataflowSoftware developerSquare numberRevision controlComputer animationLecture/Conference
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
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
Fiber bundleSocial classService (economics)Presentation of a groupView (database)File viewerFreewareLecture/Conference
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
Multiplication signObject (grammar)Graph (mathematics)TouchscreenLecture/Conference
Integrated development environmentDegree (graph theory)View (database)DataflowPresentation of a groupEndliche ModelltheorieLecture/Conference
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
View (database)TouchscreenLinearizationLogicPresentation of a groupRight angleSocial classGraph (mathematics)Object (grammar)Lecture/Conference
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
RootService (economics)Context awarenessView (database)Object (grammar)Graph (mathematics)Cartesian coordinate systemRoutingLecture/Conference
Modulo (jargon)RootCartesian coordinate systemModule (mathematics)TouchscreenObject (grammar)CASE <Informatik>Service (economics)Graph (mathematics)Physical systemLecture/Conference
RootService (economics)Context awarenessObject (grammar)CASE <Informatik>2 (number)Lecture/Conference
RootModule (mathematics)Service (economics)Context awarenessSound effectState of matterTouchscreenHierarchyGraph (mathematics)InformationLecture/ConferenceProgram flowchart
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
Library (computing)RootService (economics)Context awarenessModule (mathematics)Cartesian coordinate systemPresentation of a groupGroup actionGame controllerSet (mathematics)
Module (mathematics)RootDigital photographyRotationRepetitionTouchscreenCartesian coordinate systemDataflowMultiplication signState of matterPresentation of a groupProgram flowchart
Presentation of a groupTouchscreenRotationOverhead (computing)View (database)Lecture/Conference
RotationView (database)Service (economics)TouchscreenOvalInheritance (object-oriented programming)Structural loadStructural loadPresentation of a groupMultiplication signCountingTouchscreenLecture/Conference
RotationModule (mathematics)OvalCountingView (database)Service (economics)RepetitionPresentation of a groupDataflowService (economics)Cartesian coordinate systemCASE <Informatik>Fiber bundleProper map
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
DataflowRow (database)Group actionCuboidSquare numberTouchscreenSampling (statistics)Library (computing)Lecture/Conference
DataflowTouchscreenDefault (computer science)ImplementationCuboidTraverse (surveying)Group actionMetropolitan area networkComputer animation
RotationBit error rateGroup actionRegular graph
Direction (geometry)DataflowView (database)Convex hullOvalLetterpress printingBootingMaxima and minimaConic sectionCodeView (database)Group actionTouchscreenScaling (geometry)Social classRoundness (object)CASE <Informatik>FreewareMereologyGreatest elementComputer animation
Social classDataflowAnalog-to-digital converterState of matterDataflowSocial classGraph (mathematics)Object (grammar)Event horizonFiber bundleSerial portComputer animation
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
DisintegrationTouchscreenState of matterPresentation of a groupVideo gameCASE <Informatik>Lecture/Conference
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
Instance (computer science)Video gameCycle (graph theory)Presentation of a groupView (database)CASE <Informatik>Digital photographyLecture/Conference
DisintegrationDigital photographyOpen setOvalExecution unitFluid staticsAbstractionoutputStructural loadResultantElectronic visual displayPresentation of a groupVideo gameCycle (graph theory)View (database)RootSocial classCASE <Informatik>Cartesian coordinate systemComputer animation
Presentation of a groupResultantMedical imagingSlide ruleElectronic data processingProcess (computing)Lecture/Conference
InjektivitätUniqueness quantificationFlow separationModule (mathematics)RootData managementCASE <Informatik>Set (mathematics)InjektivitätInstance (computer science)Lecture/Conference
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
DataflowArchitectureView (database)LogicExecution unitView (database)DataflowPresentation of a groupEndliche ModelltheorieLogicComputer animationLecture/Conference
Object (grammar)Point (geometry)DataflowGraph (mathematics)Cartesian coordinate systemLogicService (economics)Flow separationLecture/Conference
Sampling (statistics)Prisoner's dilemmaMobile appDataflowCodePoint (geometry)Cartesian coordinate systemLibrary (computing)Set (mathematics)Projective planeSquare numberFrame problemTouchscreenVideo gameCycle (graph theory)Lecture/ConferenceComputer animation
TouchscreenLecture/Conference
Transcript: English(auto-generated)
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
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
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
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
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
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
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
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
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
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
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,
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,
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?
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
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
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
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
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,
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
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,
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,
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
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,
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
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.
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.
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
a very thin object, or your object graph is very thin. And yeah, based on the MVP concept,
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
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
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
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
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
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.
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,
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,
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,
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,
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
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,
so that any, like in the case of the object, I'll just show an example in a second.
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
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
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
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
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.
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,
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,
each time you go in between, we increment the counter, that's just some value I'm keeping
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
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
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,
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,
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
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
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
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,
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
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,
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,
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,
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
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,
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
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,
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
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,
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
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,
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
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
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,
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,
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
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
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,
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
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
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
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.
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,
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
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
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
update the nice image from the previous slide. Another thing because of the dependency injection and just the capabilities that mortar kind of brings,
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
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,
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
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.
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
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,
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
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
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
going to play with it. Okay thank you, it's all done.