I have a Mortar application, with a MortarActivityScope as the first child under the root scope. The MortarActivityScope has an ActivityScope which @Provides an activity for injected classes:
@Module(addsTo = ApplicationModule.class, injects = {Foo.class, SomePresenter.class, AnotherPresenter.class})
public class ActivityModule {
private final Activity activity;
public ActivityModule(Activity activity) {
this.activity = activity;
}
@Provides Activity provideActivity() {
return activity;
}
}
public class Foo {
private final Activity activity;
@Inject(Activity activity) {
this.activity = activity;
}
public void doSomethingWithActivity() {
// do stuff with activity: findViewById(), getWindow(), mess with action bar etc.
}
}
This is fine until an orientation change happens. In the Mortar sample project, the Activity scope is not destroyed on orientation changes. This is presumably to allow @Singleton presenters, screens etc. to persist across orientation changes. You can see this in the onDestroy() method in the sample project's main activity:
@Override protected void onDestroy() {
super.onDestroy();
actionBarOwner.dropView(this);
// activityScope may be null in case isWrongInstance() returned true in onCreate()
if (isFinishing() && activityScope != null) {
MortarScope parentScope = Mortar.getScope(getApplication());
parentScope.destroyChild(activityScope);
activityScope = null;
}
}
}
However, doing it this way means that the old ObjectGraph persists across orientation changes. I have observed that Mortar.requireActivityScope
does not replace the module from the old activity scope with the new module provided by the new Blueprint. Instead, the object graph retains a reference to the previous module, including the destroyed Activity.
public class MyActivity extends Activity implements Blueprint {
@Inject foo;
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MortarScope parentScope = Mortar.getScope(getApplication());
activityScope = Mortar.requireActivityScope(parentScope, this);
Mortar.inject(this, this);
foo.doSomethingWithActivity(); //fails, because activity injected by object graph is destroyed
}
@Override
public String getMortarScopeName() {
return getClass().getName();
}
@Override
public Object getDaggerModule() {
return new ActivityModule(this);
}
}
The Mortar sample activity seems to get around this by not including a @Provides Activity
method in the main module. But shouldn't the MortarActivityScope
be able to inject an Activity? What's the preferred way to do this, without losing all of your singleton objects (Presenter
objects, etc.) on orientation change?