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 the 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 the 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 onBindViewHolderwe 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…

 

LEAVE A REPLY

Please enter your comment!
Please enter your name here