Dagger with Retrofit Example – Using Dependency Injection in Activity
This is the second part of Dagger with Retrofit tutorial. In the first part, we’ve achieved the hard part of how to set up dependency injection. In this article, we’re gonna see how we can use the dependencies in our Activity.
So, let’s begin with adding Dagger to our Activity. Below is the MainActivity.
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ServiceApplicationComponent component = DaggerServiceApplicationComponent.builder() .applicationContextModule(new ApplicationContextModule(this)) .build() component.inject(this); initViews(); setRecyclerViewProperties(); carCategoriesCallback = serviceUtil.getCarCategories(); }
The interesting part of this code is DaggerApplicationComponentBuilder. You see dagger automatically create a builder pattern for our Component class. In our builder class, we are providing a new instance of ApplicationContextModule because dagger restricted us to provide an instance of that Module which has a constructor parameter.
Dagger provide a way for the fields in your activity, fragments or services to be assigned references simply by annotating the field with an @Inject. After injecting the field dagger2 locate the singletons in the dependency graph to try to find the matching return type. Below is an example of how to @Inject annotation in the field.
@Inject Picasso picasso; @Inject ServiceUtil serviceUtil;
This is how you can @inject your fields into activity at the top. Now, lets’ move how you can enqueue your network request with the retrofit.
carCategoriesCallback.enqueue(this);
In enqueue function this represents callback, and for that our MainActivity has to implement callback. One more thing by doing enqueue you are using synchronous call. The synchronous method provides the ability to use return value directly because the operation blocks everything else during the network request.
Note: For non-blocking UI you have to handle the request execution in the separate thread.
Below is the code for retrofit callback interface methods.
@Override public void onResponse(@NonNull Call<CarCategoryResponse> call, @NonNull Response<CarCategoryResponse> response) { if (mainProgressBar.getVisibility() == View.VISIBLE) mainProgressBar.setVisibility(View.GONE); if (response.isSuccessful()) { if (response.body().getCarCategories() != null && response.body().getCarCategories().size() > 0) { this.carCategories.addAll(response.body().getCarCategories()); carCategoryAdapter.notifyDataSetChanged(); } else Toast.makeText(this, "No data found!", Toast.LENGTH_SHORT).show(); } else Toast.makeText(this, "Communication error internet not connect!", Toast.LENGTH_SHORT).show(); } @Override public void onFailure(@NonNull Call<CarCategoryResponse> call, @NonNull Throwable t) { if (mainProgressBar.getVisibility() == View.VISIBLE) mainProgressBar.setVisibility(View.GONE); Toast.makeText(this, "Communication error internet not connect!", Toast.LENGTH_SHORT).show(); }
If the call succeeds the callback will come into the onResponse method. If any error occurs in the request callback will go into the onFailure method. Now in the onResponse method, we need to add data in the RecyclerView Adapter.
RecyclerViewAdapter
public class CarCategoryAdapter extends RecyclerView.Adapter<CarCategoryViewHolder> { private List<CarCategoryResponse.CarCategory> carCategories; private final LayoutInflater layoutInflater; public CarCategoryAdapter(List<CarCategoryResponse.CarCategory> carCategories, final Context context) { this.carCategories = carCategories; this.layoutInflater = LayoutInflater.from(context); } @NonNull @Override public CarCategoryViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { return new CarCategoryViewHolder(layoutInflater.inflate(R.layout.list_item_single_view, parent, false)); } @Override public void onBindViewHolder(@NonNull CarCategoryViewHolder holder, int position) { CarCategoryResponse.CarCategory carCategory = carCategories.get(position); holder.getBase_fare().setText(String.valueOf("Rs ").concat(carCategory.getBaseFare())); holder.getCar_category().setText(carCategory.getName()); holder.getRate_per_km().setText(String.valueOf("Rs ").concat(carCategory.getRatePerKm())); holder.getRate_per_min().setText(String.valueOf("Rs ").concat(carCategory.getRatePerMin())); } @Override public int getItemCount() { return carCategories.size(); } }
The Adapter provides a binding for an app specific data set to views that are displayed in a RecyclerView. In the onBindViewHolder, we update the contents of itemView to reflect the item at the given position.
RecyclerViewHolder
public class CarCategoryViewHolder extends RecyclerView.ViewHolder { private TextView car_category, rate_per_min, rate_per_km, base_fare; public CarCategoryViewHolder(View itemView) { super(itemView); car_category = itemView.findViewById(R.id.car_category); rate_per_min = itemView.findViewById(R.id.rate_per_min); rate_per_km = itemView.findViewById(R.id.rate_per_km); base_fare = itemView.findViewById(R.id.base_fare); } public TextView getCar_category() { return car_category; } public TextView getRate_per_min() { return rate_per_min; } public TextView getRate_per_km() { return rate_per_km; } public TextView getBase_fare() { return base_fare; } }
The ViewHolder describes an itemView and metadata about its place within a RecyclerView. In CarCategoryViewHolder we’re simply finding the views and set it to its relevant field.
CarCategoryResponse
public class CarCategoryResponse { @SerializedName("car_categories") @Expose private List<CarCategory> carCategories; public List<CarCategory> getCarCategories() { return carCategories; } public class CarCategory { @SerializedName("id") @Expose private int id; @SerializedName("name") @Expose private String name; @SerializedName("rate_per_km") @Expose private String ratePerKm; @SerializedName("rate_per_min") @Expose private String ratePerMin; @SerializedName("base_fare") @Expose private String baseFare; @Override public String toString() { return "CarCategory{" + "id=" + id + ", name='" + name + '\'' + ", ratePerKm=" + ratePerKm + ", ratePerMin='" + ratePerMin + '\'' + ", baseFare='" + baseFare + '\'' + '}'; } public int getId() { return id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getRatePerKm() { return ratePerKm; } public String getRatePerMin() { return ratePerMin; } public String getBaseFare() { return baseFare; } } }
Alright, this was the complete example of a dagger with the retrofit. If you guys want to learn how to make a network call with retrofit and Rx-Java check out the next article.
I hope this blog gives you a good understanding of the dagger and retrofit. If you’ve any queries regarding this please do comment below.
Thank you for being here and keep reading…