3
votes

I am trying to inject my MainActivity into the Fragment. I have an Interface that is implemented in my MainActivity that will listen to events from the Fragment. So I want to Inject the MainActivity and call the event listener on it.

I have tried doing the following but has failed to do so. Just displaying the code snippets.

interface

public interface RecipeItemListener {
    void onRecipeItem();
}

MainActivity that implements the interface

public class MainActivity extends AppCompatActivity implements RecipeItemListener {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if(savedInstanceState == null) {
            getSupportFragmentManager()
                    .beginTransaction()
                    .add(R.id.main_fragment_container, RecipeListView.newInstance(), RecipeListView.TAG)
                    .commit();
        }
    }

    @Override
    public void onRecipeItem() {
        Timber.d("onRecipeItem");
    }
}

My Module that provides the MainActivity

@Module
public class RecipeListModule {
    private MainActivity mainActivity;

    public RecipeListModule(MainActivity mainActivity) {
        this.mainActivity = mainActivity;
    }

    @RecipeListScope
    @Provides
    public RecipeItemListener providesRecipeListMainActivity() {
        return mainActivity;
    }
}

My main Component

@Singleton
@Component(modules = {
        AndroidModule.class,
        NetworkModule.class})
public interface BusbyBakingComponent {
    RecipeListComponent add(RecipeListModule recipeListModule);
}

My SubComponent

@RecipeListScope
@Subcomponent(modules = {RecipeListModule.class})
public interface RecipeListComponent {
    void inject(RecipeListView target);
}

My Application class

public class BusbyBakingApplication extends Application {
    private BusbyBakingComponent applicationComponent;
    private RecipeListComponent recipeListComponent;

    @Override
    public void onCreate() {
        super.onCreate();

        applicationComponent = createApplicationComponent();
    }

    public BusbyBakingComponent createApplicationComponent() {
        return DaggerBusbyBakingComponent.builder()
                .networkModule(new NetworkModule())
                .androidModule(new AndroidModule(BusbyBakingApplication.this))
                .build();
    }

    public BusbyBakingComponent getApplicationComponent() {
        return applicationComponent;
    }

    public RecipeListComponent createRecipeListComponent(MainActivity activity) {
        recipeListComponent = applicationComponent.add(new RecipeListModule(activity));
        return recipeListComponent;
    }

    public void releaseRecipeListComponent() {
        recipeListComponent = null;
    }
}

And in My fragment this is how I am trying to inject:

@Inject MainActivity mainActivity;
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    ((BusbyBakingApplication)getActivity().getApplication())
            .createRecipeListComponent((MainActivity)getActivity())
            .inject(RecipeListView.this);
}

I keep getting the following error:

Error:(14, 8) error: [me.androidbox.busbybaking.di.RecipeListComponent.inject(me.androidbox.busbybaking.recipieslist.RecipeListView)] me.androidbox.busbybaking.recipieslist.MainActivity cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.
me.androidbox.busbybaking.recipieslist.MainActivity is injected at
me.androidbox.busbybaking.recipieslist.RecipeListView.mainActivity
me.androidbox.busbybaking.recipieslist.RecipeListView is injected at
me.androidbox.busbybaking.di.RecipeListComponent.inject(target)

Many thanks for any suggestions.

2
Don't you already get the activity in the fragment using getActivity()? - EpicPandaForce

2 Answers

2
votes

If you have a look at your module

@RecipeListScope
@Provides
public RecipeItemListener providesRecipeListMainActivity() {
    return mainActivity;
}

You provide the interface (which is good) and not MainActivity (the implementation).

Since you request MainActivity

@Inject MainActivity mainActivity;

You receive this error:

MainActivity cannot be provided [...]

because you only provide RecipeItemListener.


Switch your code from requiring MainActivity in RecipeListView to

@Inject RecipeItemListener recipeListener;

and it should work, if the rest of your setup is correct.

-1
votes

You can access activity in Fragment using getActivity() and cast it to your interface listener like this

((RecipeItemListener)getActivity()).doSomethingOnListener()

much simpler, without any unnecessary injections