An Opinionated Guide to Dependency Injection on Android (Android Dev Summit '19)


I am Manuel Bebo and I work in the Android developer relations team which means underneath Intel I work on the Android toolkit team I'm so excited to talk about dependency injection today we know it's an important topic for the committee by the way it affects your application so

we are start with a quick introduce intuition to the eye and also definitely it has two application so that everyone is on the same page then obviously we will talk about dagger and other stuff that I don't want to spoil glasses often require references to other classes to

complete some work and those references are called dependencies and every single application has to deal with dependencies one way or another so as we can see in the diagram car cannot work without an engine so we can say that engine is a dependency of car well that car

depends on engine and with dependency injection those dependencies are provided to a class in a state of decline creating them itself so instead of car building its own instance of engine engine will be provided to car for example a duration time if we see this with some code

you will see that car here has the responsibility to build its own instance of engine but not only that part of that responsibility has to know how to configure it and that might be too much for a class to do so with a pendency injection that responsibility is

taken away from the class and now that parameter is passed as a dependency and so car can keep small unfocused and for example managing its estate and not having to worry about all of that and we believe that you should always apply dependency injection principles to your application

it doesn't matter how you do it but doing it sets the fundamentals for a testable and scalable application whilst dependency injection that important first it helps you reusing code and the copying dependencies class is no longer controller the dependencies are created and therefore they can work with any

configuration and so here we can see that bypassing in different implementations of engine we can reduce car that's it we don't have to do anything else we'll have to change the source code it is also provides a good balance of loosely coupled dependencies a better balance than other

art entities can provide for example with a service locator those dependencies are a bit more loose than with the app and it also helps you refactor in your code those dependencies now become the API surface of a class a tiller creation time or compile time instead of being

hidden as an implementation detail therefore it keeps you with a smaller and more focused classes so if we see an example here we have car with a very very long source code and when you see that your class is doing more than a true probably you you can

extract that logic out of the class put it in a different class and pass it that as a dependency for example with any related work we can create class the class engine and then pass that end as a dependency now Carl reduces the yet scope and now it's

a simpler and the cognitive load to work with class is a bit lower this is what it's called single responsibility principle but if we keep iterating on this when it makes sense of course you will see that now car becomes simpler to manage and now we have a

small source code and when just focusing on what Kyle should do for example you know assembling few parts making it simple so if we want to issue allies this will happen instead of having this massive class you can exploit it out in different parts and so it is

simpler to manage and then also multiple people people can work at the same time on the app without conflicts di also helps you with testing now you can swap in different Amin implementations of a dependency to test all the difference scenarios that you want so for example here

we have a happy path and we just want to pass in a fake Angeles to check that car works ok now if you want to check how card works with a fail in engine you just have to pass a different instance with an implementation of engine work sample

this fake failing engine and that said you have to do anything else and as I said before it doesn't matter how you do dependency injection we have some recommendations to give you before so in anything I would say that these recommendations are relative and you have to use

your own judgment because every application is different now we think that for medium and large projects this reduce dagger which is a dependency injection library and this is because a barrier is built to scale and if the scales better than any other alternatives for small applications it doesn't

really matter what you do so you can use a manual di implementation you can use a service locator pattern or you can even use dagger the truth is that the sooner do a direct to your application the whether it will be and the less you will have to

refactor in the future if we see a representation of this with our graph and we compared the cost of managing your dependencies with your application size we will see that manual dependency injection starts at zero cost money grows exponentially when the app gets bigger manual dependency injection is

very important because if you try it yourself you will see all the benefits that di can provide you but then when you start adding that to a bigger application you will see a lot of boilerplate code and a lot of stuff you have to manage yourself a service

locator instead starts with a small cost but then resize tip linear slope when the app gets bigger and by the end of that you will have kind of the same problems with manual di so you will have boilerplate code you know not that good on your hand dagger

has a high starting cost it takes a while to set it up but when the app gets bigger it kind of plateaus and then that maintenance cost that you would have with the other alternatives you wouldn't have that with with dagger so for those who don't know what

that is there is a dependency injection library that helps you managing the dependencies for you so it is when I generate the code that you would have written by hand otherwise and that generation of code happens at Build time so it is performant and safe to use in

production so you are going to avoid those runtime sugar prices and it's gonna provide you correctness at Build time so in case it wasn't clear we want you to use dial and another benefit Ivan says that dagger doesn't do reflection even though reflection got faster in Andrey toward

the years not using reflection is even better but yeah actually we want you to use dial so it's a we recommend it true and we think it's the best frame without their to dependency injection because of its correctness performance and stability and we know that because we use

it in production we use it in our apps like Gmail photos and YouTube you can see how big those applications are how much they can scale however we know that dagger and dependency injection are complex topics and they have a steep learning curve but we want you to

help we want to help you in this journey to learn all of this how are we helping we as released a set of documentation to better help you understand dependency injection and dagger from the basics to the most complex topics you can see the documentation in that link

up there and it goes it assumes nothing in testers from scratch is gonna explain everything assuming that you know nothing so recommend checking it out and why are we doing this what we want to have is a common common ground for everyone to the ones to learn dependency

injection and once do you use diary in the applications nowadays if you want to do that you might have to go to different sources different samples different blog posts all of them use a different set up and all of them use dagger in a different way so it

is very difficult to understand all the topics are related together and so that's why we want to have a common guidance a common ground and we're trying to help both beginners and a more experienced users by giving good practices so just to give you a sneak peak of

what's going on you will see that the documentation is full of best practices diagrams and codes everything you would expect but that's not it we also released a new code lab we believe that the best way you have to understand or to learn a topic is we've hand

some code and so we release this code lab called using the very in run with application whereby then of the code lab you will build an application graph like this and it starts like any other application it has an initial you know manual dependency injection implemented you will

refactor to build something like this what about dagger androids die range rate is a library built on top of dagger that reduces the boilerplate code when using there are in entrepreneurial classes such as activities or fragments it was an attempt from our part to make Dyer simpler in

Android but it didn't work we heard from you we heard from you and it doesn't solve the problems that you really have in your daily jobs so we know we can do better and so we are stopping its development we we are not adding any more features to

that because we think we can do better and we can have other ways to simplify dagger and so we are trying to reduce the amount of code you have to write and we're already making some improvements done is when I tells you more about it thank you so

one of the most immediate improvements we are doing is actually making dagger work whatever bit Kotlin and you know I'm always impressed with the under community that's you all because this was something that started in the community and we took him in and in a future version of

dagger you'll be able to use its dagger CPI in a more aromatic way we're cutting so this is this wasn't you so thank you to show you what exactly we mean you'll be able to use object classes with module you could do this already using JVM static but

you shouldn't you should be able to just you know not need JVM static which creates this extra method dagger would be able to understand this other issues dagger hat would calling was qualifier notations it was like a header may situation you would add a qualifier to a property

you would end up on the getter and dagger wouldn't understand it but similarly we're trying to fix that that should just work and on a similar kind of stop yet cutting wall cars also confuse liger a lot this is our hardest problem to tackle but ideally you wouldn't

you wouldn't need that anymore so keep a lookout on a future dagger a dagger version near a future version here you will have some of these improvements and we're still working on some others like companion updates now on the longer-term approach I'm super happy to announce that we're

actually joining efforts with the dagger team to create what we think is like a better and simpler di approach it's still under construction we feel working on this and there's no way to try out but I'll show you how we're trying to solve this and some of the

ideas and more or less how it look like we think we can make bagger the eye with dagger simpler in Android by really letting you focus on your dependency declaration and specifically taking away that setup process you really set up your components once and then you kind of

like don't touch them again in a while let's walk through some code to the story what I mean in dagger usually declare your dependencies in modules you create a function and this is a pretty simple one all we're trying to say here is that for every player that

we request somewhere players an interface we want to provide an implementation the player input everything that you write in this function is important at buying sanitation the parameter the return type it tells dagger the type of definition that you're declaring the type of binding but that's a simple

one some can get pretty complicated but you know all the fire annotation multiple parameters a body with more configuration but the truth is that we really believe that everything that you write there has a meaning and it's important so the time you spent working with the AI that

development time should really go towards those definitions because that's what you keep working on as your app skills sadly that's not the only important part the truth is that there's also the injection points this is usually your activities services fragments and usually with dagger do you use the

GS or annotation to signify that you want a property to be injected you also have to do some extra work you have you got to create this component probably grab it from your application context do memory injection the reason this has to be done like this is because

there's no construction injection in your activities or services at least not on API 29 and below yeah so that's not mm yeah but if you take the i29 you know that's not a viable solution if you want to support older devices but we want you to we kind

of want you we want to burn that away we really want you to not have to deal with this setup you know it should be enough for you to tell us that you want this Android component to be an entry point into your graph to for its dependency

to be what starts getting everything from the graph not only we want to support those dependencies that you will define but we also want to provide easy hookups to other more lifecycle related things so like view model so this should be pretty seamless to do – so kind

of to summarize those entry points are definitely important but we feel like you shouldn't have to work too much towards them it would be enough for you to tell us hey I want these hundred components to be injectable please do whatever you need to do to make that

happen so if we go back to how you can only do things you have to define components with bagger you defined your modules and the component annotation and then the entry point we saw that we can represent that differently but what happened with those modules how do we

how do we link those together or if we go back to the module we feel it might be just enough for you to tell us hey I have this module that's provide minding x' and they can go into a component the thing here is that these components would

be predefined everybody needs a single ton component and everybody defines it in a different way so why isn't there one out of the box well we feel we can do that for you and I just will singleton component but for other type of lifecycle related components like activity

or service so in a way we can again take away that setup from you and you can just focus on your bindings now most of what I mentioned is on the production side but one of the benefits of VI and dagger is testing if you are doing unit

tests that's pretty simple construction injection can get you pretty far but when you're trying to do something more complicated like integration test you need a lot of work to just have production versus testing dependencies if we look at small a at a small example here we're trying to

tell test again that player that we had and with an activity and we want to see this is like a white box testing to see what happens when you when you interact with your player how yours activity react the thing here is that player can be pretty complicated

to build and there's no reason why your production bindings definition cannot also work for your testing but this is somewhat sometimes hard to do we feel we can solve this if we provide you with some test facilities that will create a component for each test so that you

can get those bindings available but not only that the true thing about the eye is that you can change part of your state so you can further configure your tests and testing cases but to do that with the I usually replace your dependency who is fake this is

way harder to do integration tests but we also think there should be a way where you can define test modules that will simply swap part of your graph only for tests so kind of to summarize we feel we can provide you a simpler D approach by again letting

you focus on those bindings definition we could have module discovery which could be great for libraries to predefined components so you don't have to worry about setting those up or to do memory injection and the life cycle of them we can improve the testing sorry with some facilities

and simply a better way to do test configurations this wouldn't be a closed thing we would actually provide API so if you really need to do some custom component we will have api's for that so if you want to fall back to your hardcore dagger you can do

that this is our jetpack dependency injection iterative it's it'll be integrative it's blue on top of Tiger integrated with dagger we're actually working with the dagger team it's obviously more opinionated in the sense that we have those predefined components and you change a bit how you do things

because I work on the jetpack team we want for our you also jetpack infections and these are basically ability to construct India your frat men have those multi bindings for B model and and even work money your worker so basically simpler integration with the rest of the art

components library so you're leaving this room what should you take away well please use the I we feel that the value that it brings you is pretty good it creates good patterns that kind of scale give it to that beggar and we know it's complicated so we have

some guidance I run it and overall we're improving the I in Android so stay tuned these are some good ideas and we want your feedback on it so come find us in the sandbox talk to us and hopefully you can shape a better future for di thank [Music]

[Applause] [Music]

Leave A Reply

Your email address will not be published.