4

I know it is possible to inject Context with Dagger. We can see examples here and here.

On the other end, there are numerous posts about not placing context on a static variable to avoid leaks. Android Studio (lint) also warms about this:

Do not place Android context classes in static fields; this is a memory leak (and also breaks Instant Run)

I understand that by injecting a Context with Dagger, we are placing it on a singleton class, so context is somehow static. Doesn't this go against the lint warning?

Injecting the context seems to create cleaner code, since you don't have to pass it to several classes (that don't need it) so that they can further pass it to other classes that need it for some reason (getting a resource for instance).

I am just concerned that this may cause some undesired leak or breaks lint in some way.

fhsilva
  • 1,217
  • 1
  • 9
  • 17
  • 1
    I tend to provide the application context. – EpicPandaForce Jun 04 '17 at 23:16
  • 1
    I'd like to point out that daggers `@Singleton` component is just a POJO and not static by itself, unless you store it in a static variable. So if you keep your singleton AppComponent with a reference to the Application within the Application, it will share the same lifecycle, and thus is not "static" – David Medenjak Jun 04 '17 at 23:37
  • I may be overusing static here. But objects created by a Singleton component will live throughout the entire application lifecycle. I believe this means we should never provide something on this component that has a shorter lifecycle (an activity context for instance). – fhsilva Jun 05 '17 at 16:18

2 Answers2

4

You should never store/reference activity context (an activity is a context) for longer than the lifetime of the activity otherwise, as you rightly say, your app will leak memory. Application context has the lifetime​ of the app on the other hand so is safe to store/reference in singletons. Access application context via context.getApplicationContext().

Pete Hendry
  • 291
  • 2
  • 7
  • Thanks. I get it. I believe the confusion comes from my current project, where POJO objects are using inject() themselves, instead of using injected constructors. So the component needs to be stored somewhere (singleton class) to be accessed from these objects. This could lead to leaks if an Activity context is in the component. – fhsilva Jun 05 '17 at 16:21
3

If you are aware of Android lifecycles and are careful to distinguish the Application Context and the Context of Activities and Services then there is no fault injecting the Context using Dagger 2.

If you are worried about the possibility of a memory leak you can use assertions to prevent injection of the wrong Context:

public class MyActivityHelper {
     private final Context context;

     @Inject
     public MyActivityHelper (Context context) {
         if (context instanceof Application) {
              throw new IllegalArgumentExecption("MyActivityHelper requires an Activity context");
         }
     }
}

Alternatively you could use Dagger 2 Qualifiers to distinguish the two so you don't accidentally inject an app Context where an Activity Context is required. Then your constructor would look something like this:

@Inject
public class MyActivityHelper (@Named("activity") Context context) {

Note also, as per David's comment, a Dagger 2 @Singelton is not necessarily a static reference.

David Rawson
  • 20,912
  • 7
  • 88
  • 124
  • I believe the @Named qualifier is avery good idea to avoid using the wrong context. I am still playing with this, but what I got from the discussion is to store only the application component (that has a Singleton scope) and not store Activity scoped components. It still leaves the question of further scopes that are less than Singleton but more than Activity. These would need to be stored somewhere to be accessed and should be carefully managed. – fhsilva Jun 05 '17 at 16:22