Search code examples
androidandroid-adapterdagger-2android-mvp

Inject the same instance of a scoped object multiple times


I have an Activity and its presenter, both being injected with an Adapter. The Activity needs the adapter to set on the RecyclerView and the presenter needs it to call update methods (eg: notifyItemChanged) when data is changed.

The problem is that because the adapter is injected twice, the presenter and the activity don't have the same instance of it. I need Dagger to create only one instance of it. However, the Adapter needs the Activity's context and has @ActivityScope to prevent memory leaks, which means I cannot also use @Singleton scope on it.

Is there something I don't understand? Is there a way to inject the adapter in both classes, without setting it manually with a setAdapter method in the presenter or the Activity? Or is there a way to limit the number of instances of Adapter created?

EDIT: Dependency injection files:

@Module
public interface MainModule {

    @ActivityContext @Binds
    Context context(MainActivity activity);

    @ActivityScope @Binds
    MainContract.Presenter presenter(MainPresenter presenter);

    // CHILD FRAGMENT
    @FragmentScope @ContributesAndroidInjector
    ChildFragment childFragment();

    @ActivityScope @Binds
    ChildContract.Presenter childPresenter(ChildPresenter presenter);

    @ActivityScope @Binds
    ChildContract.AdapterView adapterView(MyAdapter adapter);

}

ChildFragment, ChildPresenter and MyAdapter classes are annotated with @ActivityScope.

This is the only way I got it to work and seems wrong to me because ChildPresenter and MyAdapter are only used from the fragment. However, annotating them with @FragmentScope threw up error: "may not reference bindings with different scopes". Also, the fragment "provider" and and fragment itself are annotated with two different scopes?


Solution

  • In an MVP architecture, the presenter should only care about business logic. That means the the presenter does not know anything about Android stuff and does not contain any Android specific items.

    In your case you wrote that your presenter holds an adapter and calls the notifyItemChanged methode on it. This is an Android specific item and should not work that way. The view is the one responsible for holding the adapter and any interaction from the presenter to the adapter should happen via the view.

    What that means for your example:

    • the view creates and holds one single adapter
    • the view interface provides (and the activity implements) a call notifyAdapterItemChanged
    • when the presenter needs to tell the adapter that data was updated it calls the view notifyAdapterItemChanged (and the view in turn calls the adapter)

    side note: If you need the provide data the other way around (from the adapter to the presenter) I would suggest adding a special adapterInterface to the presenter that you can keep as a weakReference in the adapter.

    Hope that helps and let me know if you have any additional questions...