1

I am creating an Android Java class in which I would like to know the country and the language of the device.

I am getting that information from android.content.Context.

I am trying to inject Context into my class's constructor like this:

@Inject
public MyClass(Context context) {
    this.context = context;
}

However, I am getting this error:

Error:(26, 22) error: android.content.Context cannot be provided without an @Provides-annotated method.
android.content.Context is injected at

So where do I need to add this @Provider?

Otherwise, how could I inject the Context object into my class?

bsky
  • 19,326
  • 49
  • 155
  • 270

1 Answers1

1

Simply put, you'll need to put that into a Module that you create and list on your application's Component annotation. However, there are some nuances:

How do you get your Application instance into the graph? In most cases, you create your top-level Dagger component (annotated with @Singleton) inside a subclass of Application that you specify in the manifest, and then use a @BindsInstance method on a Component builder to set the instance of your particular Application. Then, on Application.onCreate, you can create your top-level Dagger component and set it on an Application field. This will allow your component to have the same lifecycle as your Application, making your @Singleton-scoped bindings act like VM singletons. Technically you could just pass a Context directly into a @BindsInstance method, but you'll probably want your application subclass YourApplication instead; you can get from YourApplication to Application or Context without casts, but you can't get from Context to Application or YourApplication the same way.

This @BindsInstance code is automatic if you use dagger.android's DaggerApplication, which uses a Builder superclass called AndroidInjector so you can always pass your Android-created object into the graph.

How do you get from YourApplication to Application, and Application to Context?

Dagger doesn't automatically bind superclasses, so if you have a @BindsInstance method for YourApplication, Dagger will not necessarily be able to extrapolate bindings for Application or Context. Therefore, it's very common that you'd want methods like these in an abstract Module:

@Binds abstract Application bindApplication(YourApplication yourApplication);

@Binds abstract /* @ApplicationContext */ Context bindApplicationContext(
    Application application);

Note that getApplication() and getApplicationContext() are not guaranteed to return the same things, even though they do in most modern Android implementations. See also this SO question: getApplication() vs. getApplicationContext()

Which Context do you want? Though Context is a general interface, in Android different Contexts can do different things. If you use Subcomponents as dagger.android does, you'll inherit Application bindings in your Activity's component, which is generally good but can also mean that a binding for Context will necessarily be whatever you bind at the Application level—you don't get to override it locally. For this reason, you might want to create Qualifier annotations like @ActivityContext or @ApplicationContext to differentiate them, clearly documenting for your class whether it can expect an application context or an activity context.

If you use component dependencies instead of subcomponents, you don't automatically inherit all bindings from the Application, only the ones you list on the Component (or whichever interface you list as a dependency). With this flexibility, you might choose to always make the most-local context directly injectable, and then explicitly call Context.getApplicationContext() when you want the application context in particular. However, this advantage may not be worth listing all inherited bindings on the Component, and may also introduce subtle bugs: you might inject an object in your Application's Component that gets a different Context than if you inject that same object in your Activity's Component, which causes runtime errors because the Contexts aren't able to do the same things. Proceed with caution if you go down this route.

Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251