1

I'm using Dagger to create activity specific object graphs. Within this subgraph, I make use of a Singleton MyPresentationModel.

When i exit my activity, and enter the activity again, my expectation is that a new instance of the activity specific object graph is created, which in turn would create a new instance of Singleton MyPresentationModel (by virtue of the @Singleton semantic per Dagger. See this So answer for specifics) which would then last for the life of the activity specific object graph.

However, this is not what i'm observing, every time the activity specific object graph is created, the same instance of MyPresentationModel is used. I added a debug point into the constructor of MyPresentationModel. The very first time we enter the constructor. Subsequently even on activity exits and reentries, we don't enter the constructor (and because of this the UserSession being used within my Presentation model uses the old value from the very first constructor injection).

While i can technically solve the problem by re-setting UserSession inside MyPresentaitonModel with an external public setter, I want to understand better the mechanics of the activity specific object graph creation/destruction.

By nullifying the graph in my onDestroy, does that still mean that there is a possibility of the Singletons within my subgraph being reused at a later point ? (possibly until they are truly GCed?)

Here's some code:

 // MyAppModule
 @Module(
    includes = { UserSession.class},
    injects = { MyApplication.class })
public class MyAppModule {

  private final MyApplication _app;

  MyAppModule(MyApplication app) {
    _app = app;
  }
  // ...
}


  // Main Activity

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    _activityObjectGraph = MyApplication.get()
        .getObjectGraph()
        .plus(Arrays.<Object>asList(new SubModule()).toArray());

    // Inject ourselves so subclasses will have dependencies fulfilled when this method returns.
    _activityObjectGraph.inject(this);
  }

  @Override
  protected void onDestroy() {
    _activityObjectGraph = null;
    // this eagerly allows GC, but doesn't necessarily destroy the subgraph ?
    super.onDestroy();
  }

 // SubModule
  @Module(injects = { MyPresentationModel.class, MainActivity.class },
          addsTo = MyAppModule.class,
          library = true)
  public class SubModule {}

}

// MyPresentationModel
@Singleton
public class MyPresentationModel {

  private UserSession _session;

  @Inject
  public MyPresentationModel(UserSession session) {
    _session = session;
  }

  public void someMethodThatUsesSessionInfo() {
      // _session.getUser() ...
  }
}

@weefbellington posted a very informative answer, but reading it made me realize my question was not specific and clear enough. Here's attempt 2:

MyAppModule (main graph) -> provides a Singleton UserSession

MySubModule (sub graph plused onto MyAppModule) -> provides "activity specific" Singleton MyPresentationModel which requires a UserSession (provided my MyAppModule) on construction.

I now close the activity, destroying MySubModule (and also hopefully MyPresentationModel which is a Singleton), I update UserSession with some new information.

I open MainActivity again, thus re-creating the sub-graph from MySubModule, which inturn provides a MyPresentationModel.

The issue I'm noticing is that MyPresentationModel which is the local Singleton is not being reconstructed again i.e. this part of the code:

  @Inject
  public MyPresentationModel(UserSession session) {
    _session = session;
  }

is only ever being called once. My expectation was that this part of the code would be run again, and the UserSession would be pulled again from the Main graph and since it was updated, it would hold the updated values. My question is: are Singletons within the sub-graph cached in anyway or will they always be recreated when a new activity sub-graph is spawned?

Community
  • 1
  • 1
KG -
  • 7,130
  • 12
  • 56
  • 72

1 Answers1

2

How MyPresentationModule is injected depends on how your modules are specified. For example, assume that you are injecting the class Foo:

public class Foo {
    private final MyPresentationModel model;
    @Inject
    public Foo(MyPresentationModel model) {
        this.model = model;
    }
}

If your modules are structured like (A), then the MyPresentationModel singleton will be injected into Foo by the main object graph:

EXAMPLE A

@Module(injects = { Foo.class })
public class MainModule { ... }

@Module(addsTo = MainModule.class, injects = { MyPresentationModel.class })
public class SubModule { ...}

Alternatively, if your modules are structured like (B), then the MyPresentationModel singleton will be injected into Foo by the subgraph:

EXAMPLE B

@Module
public class MainModule { ... }

@Module(addsTo = MainModule.class, injects = { Foo.class, MyPresentationModel.class })
public class SubModule { ... }

In your particular case, since you have specified that MyAppModule injects MyApplication, I would guess that you are trying to inject MyPresentationModel into your Application class. This is probably not what you want to do. You probably want inject this into your Activity class using the submodule, as in (C).

EXAMPLE C

@Module(injects = { MainActivity.class, MyPresentationModel.class },
    addsTo = MyAppModule.class,
    library = true)
public class SubModule { ... }

public class MainActivity {
    @Inject MyPresentationModel presentationModel;
    ...
}

If you do this the MyPresentationModel singleton will be bound to the Activity subgraph instead of the main graph, and should be disposed when the Activity is destroyed.

Once you have a handle on Dagger, you might want to check out Mortar, which gives you finer-grained control over creation and destruction of ObjectGraph subscopes.

weefbellington
  • 302
  • 3
  • 8
  • thanks! the distinction between Example A and Example B is particularly interesting to me.I noticed that i bungled up some of the example code i initially posted. I've since corrected it. My SubModule actually is very similar to Example C that you posted. Reading your reply made me realize that I should be a little more clear with my ask. So i'm adding that to the question. Would really appreciate your response to that. Cheers – KG - Oct 03 '14 at 18:30