Java – Use Dagger injection activities

Use Dagger injection activities… here is a solution to the problem.

Use Dagger injection activities

I

tried creating a sample application with dagger 2 using mvp and RXAndroid, everything works fine but I can’t inject the activity Below is my AppComponent

@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {
    void inject(App app);

void inject(MainActivity activity);

void inject(ResponseService service);

void inject(MainPresenter presenter);
}

Below is my module

@Module
public class AppModule {

private App app;
    public AppModule(App app) {
        this.app = app;
    }
    private static final String API_ENDPOINT = "url here";

@Provides
    @Singleton
    public ApiService apiService() {
        OkHttpClient client = new OkHttpClient();

Gson gson = new GsonBuilder().registerTypeAdapterFactory(new ClassTypeAdapterFactory())
                .registerTypeAdapter(Class.class, new ClassTypeAdapter()).create();

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(API_ENDPOINT)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .client(client)
                .build();

return retrofit.create(ApiService.class);
    }

@Provides
    @Singleton
    ResponseService responseService() {
        return new ResponseService(app.getComponent());
    }

@Provides
    @Singleton
    MainPresenter mainPresenter() {
        return new MainPresenter(app.getComponent());
    }

@Provides
    @Singleton
    EventBus eventBus() {
        return EventBus.getDefault();
    }
}

I

injected everything correctly and can use them, except ManiActivity gives me a null pointer when trying to use it below how do I inject it

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ((App) getApplicationContext())
            .getComponent()
            .inject(this);

setContentView(R.layout.activity_main);
    ButterKnife.bind(this);

initRecyclerView();
    presenter.setView(this);
}

But when trying to use it as a Context in my adapter and pass it to the Picasso library, I get the following exception java.lang.IllegalArgumentException: Context must not be null.
Here’s how I used it

@Inject
MainActivity activity;

and use it in the onBindViewHolder as shown below

Picasso.with(activity).load(response).fit().into(holder.ivCover);

My adapter code

public class ReAdapter extends RecyclerView.Adapter<ReAdapter.RViewHolder> {
    private List<Response> responseList;

@Inject
    MainActivity appContext;

public ReAdapter() {
    }

public void setResponseList(List<Response> responseList) {
        this.responseList = responseList;
        notifyDataSetChanged();
    }

@Override
    public RViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.response_item, parent, false);
        return new RViewHolder(view);
    }

@Override
    public void onBindViewHolder(RViewHolder holder, int position) {
        final Response response = responseList.get(position);
            Picasso.with(appContext).load(response.getValue().toLowerCase()).fit().into(holder.ivd);
    }

@Override
    public int getItemCount() {
        return responseList != null ? responseList.size() : 0;
    }

public class RViewHolder extends RecyclerView.ViewHolder {
        @BindView(R.id.ivd)
        ImageView ivd;

public RViewHolder(View view) {
            super(view);
            ButterKnife.bind(this, itemView);
        }
    }
}

Can anyone help me with this?

Solution

  • Your activity: MainActivity does not have a @Inject annotated constructor (it can’t because it was created by the system).
  • There is no comment method @Provides in your AppModule that returns the MainActivity
  • You are injecting fields in your activity, not in your adapter.

The result is that Dagger does not know how to create objects of type MainActivity

The solution to this particular problem is to create a Picasso object Dagger even better using Picasso's application context

Update your AppModule with:

@Provides
@Singleton
Picasso providePicasso(App app) {
    return Picasso.with(app);
}

Add a field to the MainActivity:

@Inject
ReAdapter adapter;

In ReAdapter, modify the constructor and add a field for picasso:

private final Picasso picasso;

@Inject
public ReAdapter(Picasso picasso) {
    this.picasso = picasso;
}

Here Dagger can create singleton Picasso instances. ReAdapter is annotated with @Inject (using constructor injection) so Dagger knows how to create it. By adding the ReAdapter field in the MainActivity field, when you call component.inject(this), the MainActivity adapter field will be initialized.

Related Problems and Solutions