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 havea @Inject
annotated constructor (it can’t because it was created by the system). - There is no comment method
@Provides
in yourAppModule
that returnsthe 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.