Dagger Basics - Android Developers

Skip to main content Android Developers Essentials
  • Build AI experiences
  • Build AI-powered Android apps with Gemini APIs and more.
  • Get started
  • Get started
  • Start by creating your first app. Go deeper with our training courses or explore app development on your own.
  • Hello world
  • Training courses
  • Tutorials
  • Compose for teams
  • Kotlin for Android
  • Monetization with Play ↗️
  • Android Developer Verification
  • Extend by device
  • Build apps that give your users seamless experiences from phones to tablets, watches, headsets, and more.
  • Adaptive apps
  • Android XR
  • Wear OS
  • Android for Cars
  • Android TV
  • ChromeOS
  • Build by category
  • Learn to build for your use case by following Google's prescriptive and opinionated guidance.
  • Games
  • Camera & media
  • Social & messaging
  • Health & fitness
  • Productivity
  • Enterprise apps
  • Get the latest
  • Stay in touch with the latest releases throughout the year, join our preview programs, and give us your feedback.
  • Latest updates
  • Experimental updates
  • Android Studio preview
  • Jetpack & Compose libraries
  • Wear OS releases
  • Privacy Sandbox ↗️
Design & Plan
  • Excellent Experiences
  • Build the best experiences for your best users.
  • Learn more
  • UI Design
  • Design a beautiful user interface using Android best practices.
  • Design for Android
  • Mobile
  • Adaptive UI
  • XR Headsets & XR Glasses
  • AI Glasses
  • Widgets
  • Wear OS
  • Android TV
  • Android for Cars
  • Architecture
  • Design robust, testable, and maintainable app logic and services.
  • Introduction
  • Libraries
  • Navigation
  • Modularization
  • Testing
  • Kotlin Multiplatform
  • Quality
  • Plan for app quality and align with Play store guidelines.
  • Overview
  • Core value
  • User experience
  • Accessibility
  • Technical quality
  • Excellent Experiences
  • Security
  • Safeguard users against threats and ensure a secure Android experience.
  • Overview
  • Privacy
  • Permissions
  • Identity
  • Fraud prevention
Develop
  • Gemini in Android Studio
  • Your AI development companion for Android development.
  • Learn more
  • Get Android Studio
  • Core areas
  • Get the samples and docs for the features you need.
  • Samples
  • User interfaces
  • Background work
  • Data and files
  • Connectivity
  • All core areas ⤵️
  • Tools and workflow
  • Use the IDE to write and build your app, or create your own pipeline.
  • Write and debug code
  • Build projects
  • Test your app
  • Performance
  • Command-line tools
  • Gradle plugin API
  • Device tech
  • Write code for form factors. Connect devices and share data.
  • Adaptive UI
  • Wear OS
  • Android XR
  • Android Health
  • Android for Cars
  • Android TV
  • All devices ⤵️
  • Libraries
  • Browse API reference documentation with all the details.
  • Android platform
  • Jetpack libraries
  • Compose libraries
  • Google Play services ↗️
  • Google Play SDK index ↗️
Google Play
  • Play Console
  • Publish your app or game and grow your business on Google Play.
  • Go to Play Console
  • Learn more ↗️
  • Fundamentals
  • Learn how to engage users, monitize, and secure your app.
  • Play Monetization
  • Play Integrity
  • Play Policies
  • Play Programs ↗️
  • Games Dev Center
  • Develop and deliver games. Get tools, downloads, and samples.
  • Overview
  • Play Asset Delivery
  • Play Games Services
  • Play Games on PC
  • All Play guides ⤵️
  • Libraries
  • Browse API reference documentation with all the details.
  • Play Feature Delivery
  • Play In-app Updates
  • Play In-app Reviews
  • Play Install Referrer
  • Google Play services ↗️
  • Google Play SDK index ↗️
  • All Play libraries ⤵️
  • Tools & resources
  • Tools for publishing, promoting, and managing your app.
  • Android App Bundles
  • Brand & marketing
  • Play Console APIs ↗️
Community /
  • English
  • Deutsch
  • Español – América Latina
  • Français
  • Indonesia
  • Italiano
  • Polski
  • Português – Brasil
  • Tiếng Việt
  • Türkçe
  • Русский
  • עברית
  • العربيّة
  • فارسی
  • हिंदी
  • বাংলা
  • ภาษาไทย
  • 中文 – 简体
  • 中文 – 繁體
  • 日本語
  • 한국어
Android Studio
  • App architecture
Android Developers
  • Essentials
    • More
  • Design & Plan
    • More
  • Develop
    • More
  • Google Play
    • More
  • Community
  • Android Studio
  • Introduction
  • Guide to app architecture
    • About app architecture
    • Architecture recommendations
    • Learning pathway ⍈
    • App fundamentals
    • UI layer libraries
      • About the UI layer
      • UI events
      • State holders and UI state
      • State production
      • View binding
        • About view binding
        • Migrate from Kotlin synthetics to view binding
      • Data binding library
        • About data binding
        • Get started
        • Layouts and binding expressions
        • Work with observable data objects
        • Generated binding classes
        • Binding adapters
        • Bind layout views to Architecture Components
        • Two-way data binding
      • Lifecycle-aware components
        • Lifecycles
          • Handle lifecycles
          • Integrate with Compose
        • ViewModel
          • About ViewModel
          • Create ViewModels with dependencies
          • ViewModel Scoping APIs
          • Saved State module for ViewModel
          • ViewModel APIs cheat sheet
        • LiveData
        • Save UI states
        • Use Kotlin coroutines with lifecycle-aware components
      • Paging Library
        • About paging
        • Load and display paged data
        • Page from network and database
        • Transform data streams
        • Manage and present loading states
        • Test your Paging implementation
        • Migrate to Paging 3
        • Paging 2
          • About Paging 2
          • Display paged lists
          • Load paged data
    • Domain layer
    • Data layer libraries
      • About the data layer
      • Offline first
      • DataStore
      • WorkManager ⍈
    • App startup
  • Modularization
    • About modularization
    • Common patterns
  • App resources
    • About app resources
    • Handle configuration changes
    • Localization
      • Localize your app
      • Test your app with pseudolocales
      • Unicode and internationalization support
      • Language and locale resolution
      • Per-app language preferences
    • Complex XML resources
    • Resource types
      • About resource types
      • Animation
      • Color state list
      • Drawable
      • Layout
      • Menu
      • String
      • Style
      • Font
      • More types
  • App manifest file
    • About app manifests
    • <action>
    • <activity>
    • <activity-alias>
    • <application>
    • <attribution>
    • <category>
    • <compatible-screens>
    • <data>
    • <grant-uri-permission>
    • <instrumentation>
    • <intent-filter>
    • <layout>
    • <manifest>
    • <meta-data>
    • <path-permission>
    • <permission>
    • <permission-group>
    • <permission-tree>
    • <profileable>
    • <property>
    • <provider>
    • <queries>
    • <receiver>
    • <service>
    • <supports-gl-texture>
    • <supports-screens>
    • <uri-relative-filter-group>
    • <uses-configuration>
    • <uses-feature>
    • <uses-library>
    • <uses-native-library>
    • <uses-permission>
    • <uses-permission-sdk-23>
    • <uses-sdk>
  • App entry points
    • Activities
      • Introduction to activities
      • The activity lifecycle
      • Activity state changes
      • Test your app's activities
      • Tasks and the back stack
      • Processes and app lifecycle
      • Parcelables and bundles
      • Loaders
      • Recents screen
      • Restrictions on starting activities from the background
    • Add app shortcuts ⍈
  • App navigation
    • Principles of navigation
    • Navigation component
      • Overview
      • Navigation controller
      • Design your navigation graph
        • Overview
        • Dialog destinations
        • Activity destinations
        • Nested graphs
        • Deep links
        • New destination types
        • Type safety
        • Encapsulate your code
        • Global actions
        • Fragments and the Kotlin DSL
        • Use the Navigation editor
      • Use your navigation graph
        • Navigate to a destination
        • Navigate with options
        • Safe args
        • Pass data between destinations
        • Animate transitions between destinations
        • Conditional navigation
        • Interact programmatically with the Navigation component
      • The back stack
        • Overview
        • Dialogs and the back stack
        • Circular navigation and the back stack
        • Multiple back stacks
      • Integrations
        • Navigate with feature modules
        • Multi-module projects
        • Connect UI components to NavController
      • Migrate to the Navigation component
      • Test navigation
    • Custom back navigation
      • Custom back navigation
      • Predictive back gesture
      • Add support for predictive back animations
    • Responsive design
      • Handling configuration changes
      • Design for different form factors
    • Swipe between views
      • Swipe views using ViewPager2
      • Swipe views using ViewPager
    • Navigation 3
      • Overview
      • Get started
      • Understand and implement the basics
      • Save and manage navigation state
      • Modularize navigation code
      • Create custom layouts using Scenes
      • Animate between destinations
      • Apply logic or wrappers to destinations
      • Migrate from Navigation 2
    • Fragments
      • About fragments
      • Create a fragment
      • Fragment manager
      • Fragment transactions
      • Animate transitions between fragments
      • Fragment lifecycle
      • Saving state with fragments
      • Communicate with fragments
      • Working with the app bar
      • Displaying dialogs with DialogFragment
      • Debug your fragments
      • Test your fragments
    • Deep links
      • About deep links
      • Create deep links
      • Implement App Links
        • About App Links
        • Add intent filters
        • Configure website associations
        • Verify App Links
        • Test App Links
        • Troubleshoot
        • App Links FAQ
        • Developer tools
    • Interact with other apps
      • About interacting with other apps
      • About intents and intent filters
      • About common intents
      • Google Maps intents for Android
      • Send users to another app
      • Get a result from an activity
      • Allow other apps to start your activity
      • Limit loading in on-device Android containers
      • Package visibility
        • About package visibility
        • Know which packages are visible automatically
        • Declare package visibility needs
        • Fulfill common use cases
        • Test package visibility
  • Dependency injection
    • About dependency injection
    • Manual dependency injection
    • Dependency injection with Hilt
    • Hilt in multi-module apps
    • Use Hilt with other Jetpack libraries
    • Hilt testing guide
    • Hilt and Dagger annotations cheat sheet
    • Dagger
      • Dagger basics
      • Using Dagger in Android apps
      • Using Dagger in multi-module apps
  • Android Developers
  • Design & Plan
  • App architecture
Dagger basics Stay organized with collections Save and categorize content based on your preferences.

Manual dependency injection or service locators in an Android app can be problematic depending on the size of your project. You can limit your project's complexity as it scales up by using Dagger to manage dependencies.

Dagger automatically generates code that mimics the code you would otherwise have hand-written. Because the code is generated at compile time, it's traceable and more performant than other reflection-based solutions such as Guice.

Note: Use Hilt for dependency injection on Android. Hilt is built on top of Dagger and it provides a standard way to incorporate Dagger dependency injection into an Android application.

Benefits of using Dagger

Dagger frees you from writing tedious and error-prone boilerplate code by:

  • Generating the AppContainer code (application graph) that you manually implemented in the manual DI section.

  • Creating factories for the classes available in the application graph. This is how dependencies are satisfied internally.

  • Deciding whether to reuse a dependency or create a new instance through the use of scopes.

  • Creating containers for specific flows as you did with the login flow in the previous section using Dagger subcomponents. This improves your app's performance by releasing objects in memory when they're no longer needed.

Dagger automatically does all of this at build time as long as you declare dependencies of a class and specify how to satisfy them using annotations. Dagger generates code similar to what you would have written manually. Internally, Dagger creates a graph of objects that it can reference to find the way to provide an instance of a class. For every class in the graph, Dagger generates a factory-type class that it uses internally to get instances of that type.

At build time, Dagger walks through your code and:

  • Builds and validates dependency graphs, ensuring that:

    • Every object's dependencies can be satisfied, so there are no runtime exceptions.
    • No dependency cycles exist, so there are no infinite loops.
  • Generates the classes that are used at runtime to create the actual objects and their dependencies.

A simple use case in Dagger: Generating a factory

To demonstrate how you can work with Dagger, let's create a simple factory for the UserRepository class shown in the following diagram:

Define UserRepository as follows:

Kotlin

classUserRepository( privatevallocalDataSource:UserLocalDataSource, privatevalremoteDataSource:UserRemoteDataSource ){...}

Java

publicclass UserRepository{ privatefinalUserLocalDataSourceuserLocalDataSource; privatefinalUserRemoteDataSourceuserRemoteDataSource; publicUserRepository(UserLocalDataSourceuserLocalDataSource,UserRemoteDataSourceuserRemoteDataSource){ this.userLocalDataSource=userLocalDataSource; this.userRemoteDataSource=userRemoteDataSource; } ... }

Add an @Inject annotation to the UserRepository constructor so Dagger knows how to create a UserRepository:

Kotlin

// @Inject lets Dagger know how to create instances of this object classUserRepository@Injectconstructor( privatevallocalDataSource:UserLocalDataSource, privatevalremoteDataSource:UserRemoteDataSource ){...}

Java

publicclass UserRepository{ privatefinalUserLocalDataSourceuserLocalDataSource; privatefinalUserRemoteDataSourceuserRemoteDataSource; // @Inject lets Dagger know how to create instances of this object @Inject publicUserRepository(UserLocalDataSourceuserLocalDataSource,UserRemoteDataSourceuserRemoteDataSource){ this.userLocalDataSource=userLocalDataSource; this.userRemoteDataSource=userRemoteDataSource; } }

In the above snippet of code, you're telling Dagger:

  1. How to create a UserRepository instance with the @Inject annotated constructor.

  2. What its dependencies are: UserLocalDataSource and UserRemoteDataSource.

Now Dagger knows how to create an instance of UserRepository, but it doesn't know how to create its dependencies. If you annotate the other classes too, Dagger knows how to create them:

Kotlin

// @Inject lets Dagger know how to create instances of these objects classUserLocalDataSource@Injectconstructor(){...} classUserRemoteDataSource@Injectconstructor(){...}

Java

publicclass UserLocalDataSource{ @Inject publicUserLocalDataSource(){} } publicclass UserRemoteDataSource{ @Inject publicUserRemoteDataSource(){} }

Dagger components

Dagger can create a graph of the dependencies in your project that it can use to find out where it should get those dependencies when they are needed. To make Dagger do this, you need to create an interface and annotate it with @Component. Dagger creates a container as you would have done with manual dependency injection.

Inside the @Component interface, you can define functions that return instances of the classes you need (i.e. UserRepository). @Component tells Dagger to generate a container with all the dependencies required to satisfy the types it exposes. This is called a Dagger component; it contains a graph that consists of the objects that Dagger knows how to provide and their respective dependencies.

Kotlin

// @Component makes Dagger create a graph of dependencies @Component interfaceApplicationGraph{ // The return type of functions inside the component interface is // what can be provided from the container funrepository():UserRepository }

Java

// @Component makes Dagger create a graph of dependencies @Component publicinterface ApplicationGraph{ // The return type of functions inside the component interface is // what can be consumed from the graph UserRepositoryuserRepository(); }

When you build the project, Dagger generates an implementation of the ApplicationGraph interface for you: DaggerApplicationGraph. With its annotation processor, Dagger creates a dependency graph that consists of the relationships between the three classes (UserRepository, UserLocalDatasource, and UserRemoteDataSource) with only one entry point: getting a UserRepository instance. You can use it as follows:

Kotlin

// Create an instance of the application graph valapplicationGraph:ApplicationGraph=DaggerApplicationGraph.create() // Grab an instance of UserRepository from the application graph valuserRepository:UserRepository=applicationGraph.repository()

Java

// Create an instance of the application graph ApplicationGraphapplicationGraph=DaggerApplicationGraph.create(); // Grab an instance of UserRepository from the application graph UserRepositoryuserRepository=applicationGraph.userRepository();

Dagger creates a new instance of UserRepository every time it's requested.

Kotlin

valapplicationGraph:ApplicationGraph=DaggerApplicationGraph.create() valuserRepository:UserRepository=applicationGraph.repository() valuserRepository2:UserRepository=applicationGraph.repository() assert(userRepository!=userRepository2)

Java

ApplicationGraphapplicationGraph=DaggerApplicationGraph.create(); UserRepositoryuserRepository=applicationGraph.userRepository(); UserRepositoryuserRepository2=applicationGraph.userRepository(); assert(userRepository!=userRepository2)

Sometimes, you need to have a unique instance of a dependency in a container. You might want this for several reasons:

  1. You want other types that have this type as a dependency to share the same instance, such as multiple ViewModel objects in the login flow using the same LoginUserData.

  2. An object is expensive to create and you don't want to create a new instance every time it's declared as a dependency (for example, a JSON parser).

In the example, you might want to have a unique instance of UserRepository available in the graph so that every time you ask for a UserRepository, you always get the same instance. This is useful in your example because in a real-life application with a more complex application graph, you might have multiple ViewModel objects depending on UserRepository and you don't want to create new instances of UserLocalDataSource and UserRemoteDataSource every time UserRepository needs to be provided.

In manual dependency injection, you do this by passing in the same instance of UserRepository to the constructors of the ViewModel classes; but in Dagger, because you are not writing that code manually, you have to let Dagger know you want to use the same instance. This can be done with scope annotations.

Scoping with Dagger

You can use scope annotations to limit the lifetime of an object to the lifetime of its component. This means that the same instance of a dependency is used every time that type needs to be provided.

To have a unique instance of a UserRepository when you ask for the repository in ApplicationGraph, use the same scope annotation for the @Component interface and UserRepository. You can use the @Singleton annotation that already comes with the javax.inject package that Dagger uses:

Kotlin

// Scope annotations on a @Component interface informs Dagger that classes annotated // with this annotation (i.e. @Singleton) are bound to the life of the graph and so // the same instance of that type is provided every time the type is requested. @Singleton @Component interfaceApplicationGraph{ funrepository():UserRepository } // Scope this class to a component using @Singleton scope (i.e. ApplicationGraph) @Singleton classUserRepository@Injectconstructor( privatevallocalDataSource:UserLocalDataSource, privatevalremoteDataSource:UserRemoteDataSource ){...}

Java

// Scope annotations on a @Component interface informs Dagger that classes annotated // with this annotation (i.e. @Singleton) are scoped to the graph and the same // instance of that type is provided every time the type is requested. @Singleton @Component publicinterface ApplicationGraph{ UserRepositoryuserRepository(); } // Scope this class to a component using @Singleton scope (i.e. ApplicationGraph) @Singleton publicclass UserRepository{ privatefinalUserLocalDataSourceuserLocalDataSource; privatefinalUserRemoteDataSourceuserRemoteDataSource; @Inject publicUserRepository(UserLocalDataSourceuserLocalDataSource,UserRemoteDataSourceuserRemoteDataSource){ this.userLocalDataSource=userLocalDataSource; this.userRemoteDataSource=userRemoteDataSource; } }

Alternatively, you can create and use a custom scope annotation. You can create a scope annotation as follows:

Kotlin

// Creates MyCustomScope @Scope @MustBeDocumented @Retention(value=AnnotationRetention.RUNTIME) annotationclassMyCustomScope

Java

// Creates MyCustomScope @Scope @Retention(RetentionPolicy.RUNTIME) public@interfaceMyCustomScope{}

Then, you can use it as before:

Kotlin

@MyCustomScope @Component interfaceApplicationGraph{ funrepository():UserRepository } @MyCustomScope classUserRepository@Injectconstructor( privatevallocalDataSource:UserLocalDataSource, privatevalservice:UserService ){...}

Java

@MyCustomScope @Component publicinterface ApplicationGraph{ UserRepositoryuserRepository(); } @MyCustomScope publicclass UserRepository{ privatefinalUserLocalDataSourceuserLocalDataSource; privatefinalUserRemoteDataSourceuserRemoteDataSource; @Inject publicUserRepository(UserLocalDataSourceuserLocalDataSource,UserRemoteDataSourceuserRemoteDataSource){ this.userLocalDataSource=userLocalDataSource; this.userRemoteDataSource=userRemoteDataSource; } }

In both cases, the object is provided with the same scope used to annotate the @Component interface. Thus, every time you call applicationGraph.repository(), you get the same instance of UserRepository.

Kotlin

valapplicationGraph:ApplicationGraph=DaggerApplicationGraph.create() valuserRepository:UserRepository=applicationGraph.repository() valuserRepository2:UserRepository=applicationGraph.repository() assert(userRepository==userRepository2)

Java

ApplicationGraphapplicationGraph=DaggerApplicationGraph.create(); UserRepositoryuserRepository=applicationGraph.userRepository(); UserRepositoryuserRepository2=applicationGraph.userRepository(); assert(userRepository==userRepository2)

Conclusion

It is important to be aware of Dagger's benefits and the basics of how it works before you can use it in more complicated scenarios.

In the next page, you'll learn how to add Dagger to an Android application.

Content and code samples on this page are subject to the licenses described in the Content License. Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.

Last updated 2025-02-10 UTC.

[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2025-02-10 UTC."],[],[]]
  • X X Follow @AndroidDev on X
  • YouTube YouTube Check out Android Developers on YouTube
  • LinkedIn LinkedIn Connect with the Android Developers community on LinkedIn
  • More Android

    • Android
    • Android for Enterprise
    • Security
    • Source
    • News
    • Blog
    • Podcasts
  • Discover

    • Gaming
    • Machine Learning
    • Health & Fitness
    • Camera & Media
    • Privacy
    • 5G
  • Android Devices

    • Large screens
    • Wear OS
    • ChromeOS devices
    • Android for cars
    • Android TV
  • Releases

    • Android 15
    • Android 14
    • Android 13
    • Android 12
    • Android 11
    • Android 10
    • Pie
  • Documentation and Downloads

    • Android Studio guide
    • Developers guides
    • API reference
    • Download Studio
    • Android NDK
  • Support

    • Report platform bug
    • Report documentation bug
    • Google Play support
    • Join research studies
Google Developers
  • Android
  • Chrome
  • Firebase
  • Google Cloud Platform
  • All products
  • Privacy
  • License
  • Brand guidelines
  • Manage cookies
  • Get news and tips by email Subscribe
  • English
  • Deutsch
  • Español – América Latina
  • Français
  • Indonesia
  • Italiano
  • Polski
  • Português – Brasil
  • Tiếng Việt
  • Türkçe
  • Русский
  • עברית
  • العربيّة
  • فارسی
  • हिंदी
  • বাংলা
  • ภาษาไทย
  • 中文 – 简体
  • 中文 – 繁體
  • 日本語
  • 한국어

Tag » What Is Dagger Used For