An opinionated guide to Dependency Injection on Android (Android Dev Summit '19)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

This is clearly the winner news for me, a simple way to inject viewmodel/workmanager, example on how to use scope, this jetpack di initiative looks incredible to me! Can't wait for this

πŸ‘οΈŽ︎ 17 πŸ‘€οΈŽ︎ u/nitrog42 πŸ“…οΈŽ︎ Oct 24 2019 πŸ—«︎ replies
πŸ‘οΈŽ︎ 10 πŸ‘€οΈŽ︎ u/Cultist πŸ“…οΈŽ︎ Oct 25 2019 πŸ—«︎ replies

So if my app has more than 4 screens I need dagger? Where does this even come from?

I have more than 15 screens and I don't use dagger. Dependency Injection is such a simple thing, I don't need a framework for this.

How do I do it then?

I simply create a singleton class named `MyAppContext` (call it whatever you want) and in there I (lazily) initialize my repositories and other things that need to be injected in view models.

Then I pass the dependencies to the view model's factory when initializing it in activities / fragments. Simple as that.

πŸ‘οΈŽ︎ 13 πŸ‘€οΈŽ︎ u/minas1 πŸ“…οΈŽ︎ Oct 25 2019 πŸ—«︎ replies

Oddly, not much of a guide. It's pretty much just "Use Dagger." Not that I'm against the advice (as an avid Dagger user myself), but for those who don't know how to use Dagger (and by god, most don't), this doesn't really help.

πŸ‘οΈŽ︎ 15 πŸ‘€οΈŽ︎ u/Pzychotix πŸ“…οΈŽ︎ Oct 25 2019 πŸ—«︎ replies

Oh look! a codelab with dagger that actually injects ViewModels! Woo!

For simplicity, LoginViewModel is not an Android Architecture Components ViewModel; it's just a regular class that acts as a ViewModel.

Ah... right... so we have a codelab that skips the bits people actually need help with.

Surprise, surprise.

πŸ‘οΈŽ︎ 2 πŸ‘€οΈŽ︎ u/GoldDog πŸ“…οΈŽ︎ Oct 27 2019 πŸ—«︎ replies

Been leveraging manual DI for two years now in Kotlin and haven’t missed Dagger one bit!

πŸ‘οΈŽ︎ 6 πŸ‘€οΈŽ︎ u/ZakTaccardi πŸ“…οΈŽ︎ Oct 25 2019 πŸ—«︎ replies

Does someone have a link to a good tuto of the basics of dependency injection ? I've never done that and I don't really know what it is or how it works

πŸ‘οΈŽ︎ 1 πŸ‘€οΈŽ︎ u/Playdric πŸ“…οΈŽ︎ Oct 25 2019 πŸ—«︎ replies
Captions
[MUSIC PLAYING] MANUEL VIVO: I am Manuel Vivo, and I work in the Android Developer Relations team, which means-- DANIEL SANTIAGO: I'm Daniel Santiago. I work on the Android Toolkit team. MANUEL VIVO: I'm so excited to talk about Dependency Injection today. We know it's an important topic for the community with the way it affects your application. So we'll start with a quick introduction to DI, and also the [INAUDIBLE] it has to your 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. Classes 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, the car cannot work without an engine. So we can say that engine is a dependency of car, or that car depends on engine. And with dependency injection, those dependencies are provided to a class instead of the class creating them itself. So instead of car building its own instance of engine, engine will be provided to car-- for example, at creation 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-- apart from that responsibility, it has to know how to configure it. And that might be too much for the class to do. And so with dependency injection, that responsibility is taken away from the class. And now that parameter is passed as a dependency, and so car can keep small and focused-- for example, managing its state 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. Why is dependency injection that important? First, it helps you reusing code and decoupling dependencies. Classes no longer control how the dependencies are created, and therefore they can work with any configuration. And so here we can see that by passing in different implementations of engine, we can reuse car. That said, we don't have to do anything else. We don't have to change the source code. It is also provides a good balance of loosely coupled dependencies-- a better balance than other alternatives can provide. For example, with a service locator, those dependencies are a bit more loose than with DI. And it also helps you refactoring your code. Those dependencies now become the API surface of our class until their creation time or compile time, instead of being hidden as an implementation detail. Therefore, it keeps you with smaller and more focused classes. So if we see in an example here, we have car with very, very long source code. And when you see that your class is doing more than it should, probably you can extract that logic out of the class, put it in a different class, and pass it as a dependency. For example, with engine-related work, we can create class-- the class engine-- and then pass that in as a dependency. Now car reduces its scope, and now it's simpler. And the cognitive load to work with class is a bit lower. This is what is 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 smaller source code, and we're just focusing on what car should do. For example, assembling few parts, making it simple. So if we want to [INAUDIBLE] this, instead of having this massive class, you can split it out in different parts, and so it's simpler to manage. And then also multiple people can work at the same time on the app without conflicts. DI also helps you with testing. Now you can swap in different implementations of a dependency to test all the different scenarios that you want. So for example, here we have a happy path, and we just want to pass in a fake engine just to check that car works OK. Now, if you want to check how car works with a failing engine, you just have to pass a different instance with an implementation of engine. For example, this fake failing engine. And that's it-- you don't have to do anything else. And as I said before, it doesn't matter how you do dependency injection. However, we have some recommendations to give you. Before showing 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, you should use Dagger, which is our dependency injection library. And this is because Dagger is built to scale, and it 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, and you can use a service locator pattern, or you can even use Dagger. The truth is that the sooner you add Dagger to your application, the better it will be and the less you we have to refactor it in the future. If we see a representation of this with our graph, and we compare the cost of managing your dependencies with your application size, you will see that manual dependency injection starts at zero cost. But it 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 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, it starts with a small cost, but then there is a steep 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-- not that good. On the other hand, Dagger has a higher 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 Dagger. So for those who don't know what Dagger is, Dagger is a dependency injection library that helps you manage the dependencies for you. So it is going to 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 sort of prices, and it's going to provide you correctness at build time. So in case it wasn't clear, we want you to use Dagger. [LAUGHING] And another benefit I didn't say is that Dagger doesn't use reflection. Even though reflection got faster in Android over the years, not using reflection is even better. But yeah, actually, we want you to use Dagger. So it's our recommended tool. And we think it's the best framework out there to do dependency injection because of its correctness, performance, and scalability. 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, and 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. Well, how are we helping? We just 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 assumes nothing. It starts from scratch. It's going to explain everything assuming that you know nothing. So I recommend checking it out. And why are we doing this? What we want to have is a common ground for everyone that wants to learn dependency injection, and wants to use Dagger in applications. [INAUDIBLE] this-- if you want to do that, you might have two or three 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 and relate them 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 more experienced users by giving good practices. So just to give you a sneak peek 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 Codelab. We believe that the best way you have to understand or to learn a topic is with hands-on code. And so we released this Codelabs called "Using Dagger in your Android Application," where by the end of the Codelab, you will build an application graph like this. And it starts like any other application. It has an initial manual dependency injection implementation that you will refactor to build something like this. What about dagger-android? dagger-android is a library built on top of Dagger that reduces the boilerplate code when using Dagger in Android framework classes, such as activities or fragments. It was an attempt on our part to make Dagger simpler in Android, but it didn't work. We heard from you-- [NERVOUS LAUGH] [LAUGHING] --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 are not adding any more features to do 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 are really making some improvements. Danny is going to tell you more about it. DANIEL SANTIAGO: Thank you. So one of the most immediate improvements we are doing is actually making Dagger work better with Kotlin. And I'm always impressed with the Android community-- that's you all-- because this was something that started in the community, and we took it in. And in a future version of Dagger, you'll be able to use Dagger's API in a more idiomatic way with Kotlin. So this was on 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 JvmStatic, but you shouldn't. You should be able to just not need JvmStatic, which creates this extra method. Dagger will be able to understand this. Other issues Dagger had with Kotlin was qualifier notation. It was like hit or miss situation. You would add a qualifier to a property-- it 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 subject, Kotlin wildcards also confused Dagger a lot. This is a part of this problem to tackle, but ideally, you wouldn't need that anymore. So keep a lookout on a future Dagger version near you. It'll have some of these improvements, and we're still working on some others, like companion objects. 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 a better and simpler DI approach. It's still under construction. We're still working on this, and there's no library 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'll look like. We think we can make DI 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 illustrate what I mean. In Dagger, you 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-- Player is an interface-- we want to provide an implementation-- the PlayerImpl. Everything that you write in this function is important-- that @Binds annotation, 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-- qualifier 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 DI, that development time should really go towards those definitions, because that's what you keep working on as your app scales. Sadly, that's not the only important part. The truth is there's also the injection points. This is usually your activities, services, fragments. And usually with Dagger, you use the JSR annotation to signify that you want a property to be injected. But you also have to do some extra work. You have 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-- [LAUGHING] Mmm-- yeah. But if you take API 29, that's not a viable solution if you want to support older devices. But we kind of want you-- we want to burn that away. We really want you to not have to deal with this setup. It should be enough for you to tell us that you want this Android component to be an entry point into your graph, for its dependency to be what starts getting everything from the graph. Not only do we want to support those dependencies that you define, but we also want to provide easy hookups to other more lifecycle related things, like view model. So this should be pretty seamless to do, too. 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 Android components to be injectable-- please do whatever you need to do to make that happen. So if you go back to how you currently do things, you have to define components with Dagger, you define your modules in 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 link those together? Well, if we go back to a module, we feel it might be just enough for you to tell us, hey, I have this module that provides bindings, and they can go into component. The thing here is that these components will be predefined. Everybody needs a singleton 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 not just for singleton component, but for other types of lifecycle related components, like a [? TVT ?] 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 mention is on the production side, but one of the benefits of DI in 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 tests, you need a lot of work to just have production versus testing dependencies. If we look at a small example here, we're trying to test again that player that we have with an activity. This is like a white box test, so we want to see what happens when you interact with your player, how your activity reacts. 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 utilities that will create a component for each test so that you can get those bindings available. But not only that, the true thing about DI is that you can change part of your state so you can further configure your test and test new cases. But to do that with DI, usually replace your dependency with fake. But 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 parts of your graph only for tests. So kind of to summarize, we feel we can provide you a simpler DI approach by, again, letting you focus on those binding definition. We could have module discovery, which could be great for libraries too. Predefined components so you don't have to worry about setting those up or to do memory injection. And the lifecycle of them, we can improve the testing story with some test utilities, and simply a better way to do test configurations. This wouldn't be a closed thing. We would actually provide APIs. So if you really need to do some custom component, we will have APIs for that. So if you want to fall back to your hardcore Dagger, you can do that. This is our Jetpack dependency injection initiative. It'll be integrated-- it's built on top of Dagger-- 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 thing, we want to provide you also Jetpack extensions. And these are basically abilities to construct your fragment, have those multi-bindings for view model, and even manage your workers. So basically simpler integration with the rest of the [? R ?] components library. So you're leaving this room-- what should you take away? Well, please use DI. We feel that the value that it brings you is pretty good. It creates good patterns that can scale. Give it a shot at Dagger. And we know it's complicated, so we have some guidance around it. And overall, we're improving DI 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, we can shape a better future for DI. Thank you. [MUSIC PLAYING] [APPLAUSE]
Info
Channel: Android Developers
Views: 39,507
Rating: 4.8097754 out of 5
Keywords: type: Conference Talk (Full production);, pr_pr: Android, purpose: Educate
Id: o-ins1nvbDg
Channel Id: undefined
Length: 19min 28sec (1168 seconds)
Published: Thu Oct 24 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.