I have custom scope:
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface PerActivity { }
and component which uses this annotation:
@PerActivity
@Component(modules = {ActivityModule.class}, dependencies = AppComponent.class)
public interface ActivityComponent {
void inject(MainActivity mainActivity);
}
and module which provides MainPresenter dependency:
@Module
public class ActivityModule {
@PerActivity
@Provides
public MainPresenter provideMainPresenter(){
return new MainPresenter();
}
}
This is MainActivity to which MainPresenter is injected:
public class MainActivity extends AppCompatActivity implements MainView {
@PerActivity
@Inject
MainPresenter mainPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerActivityComponent.builder()
.appComponent(DaggerAppComponent.builder().build())
.build()
.inject(this);
}
}
My problem: presenter is recreated after a configuration change (orientation change).
My question: how to make it create only once for one activity?
Dagger creates Java code that doesn't do any magic. It's some classes that can do some stuff, but they don't read/write global state or have other side effects. If you create a component, then you create all the objects that it contains. A @PerActivity
scoped object provided by one component will never be the same as the one provided from another component of the same scope.
MyComponent.create().getPresenter() == MyComponent.create().getPresenter() // always false (with same scope)
This said, you have one major problem in your code sample, namely that you have an AppComponent
, but you're keep recreating it, which is most likely not what you intended or should do. This will re-create every @Singleton
for every Activity.
DaggerActivityComponent.builder()
.appComponent(DaggerAppComponent.builder().build()) // DON'T !!
.build()
.inject(this);
You need to cache this component in your Application
class and retrieve it, e.g. something like ((MyApp) getApplication).getComponent()
. Otherwise none of your @Singleton
classes get reused.
All this said, a presenter that is scoped @PerActivity
will always be a new object when you create a new ActivityComponent (DaggerActivityComponent.build()
) in your onCreate
method. You recreate the component, and that new component will create new objects. This is the intended behavior, because otherwise you will get memory leaks and other unintended side effects. (Imagine the presenter kept a reference to the activity! Memory will leak, and UI updates will crash or be ignored.)
To reuse the same presenter you have to move the presenter up in scope. You can either make the presenter a @Singleton
and keep it in your AppComponent
, or you can try to find a way to add another layer of components in-between (AppComponent -> ActivityCacheComponent -> ActivityComponent
), but most project that I have seen won't add this in-between layer as it adds a lot of complexity. You either have singletons that hold data and should be long-lived, or you have presenters that are cheap to create and can be easily recreated along with the Activity.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With