Posts Tagged

retrofit

Android Architecture Components Part 2 – Dependency Injection

As promised, part two is here. ? Before we get our hands dirty, let’s do a quick recap. In the previous post, we created a simple app that displays a list of user names using Android architecture components library. We divided our app into the following layers for better code responsibility and separation of concerns:

  1. View/UI layer
  2. ViewModel layer

This worked pretty well but our data was hard coded. In this series, we will setup Retrofit for API Calls & Dagger 2 to add Dependency Injection to our app and use TMDB API to get some data. With that said, our new architecture will look like below.

Picture from: Android developers site

Before We Begin …

Who the hell is Dagger and what is Dependency Injection? Worry not we will walk through this first. So let’s define some terms.

Dependency: This is when a  class has a dependency on another class, if it uses an instance of this class. We call this a _class dependency.

Dependency Injection: Also known as DI. Dependency Injection is a technique whereby one object supplies the dependencies of another object. This means an object creating its dependendencies via new operator is strictly prohibited.

We will be using Dagger 2 for DI.

Dagger Annotations

Dagger 2 uses the following annotations:

  • @Moduleand @Provides: define classes and methods which provide dependencies.
  • @Inject: request dependencies. Can be used on a constructor, a field, or a method.
  • @Component: enable selected modules and used for performing dependency injection
  • @Singleton : annotation ensures the class instance as singleton across the dependency graph.

Dependency Injection can be a beast and I don’t want to dive into it. There are a couple of articles that talk about this. I’ll add them at the end of the article. ?

Project Structure

For some organization, We’ll handle injection in a package called di.

Let’s Code

The source code is available on Github.

You’ll need to add dagger dependencies to your build.gradle file

Creating Modules

We’ll set up a couple of module classes.

  1. App Module: This will ensure that TmdbService will be a singleton throughout our app.
  2. NetworkModule: This helps us setup retrofit and logging.
  3. ViewModelModule: Module to set up our viewmodels.

Let’s set up our modules:

NetworkModule.

We’ve done a couple of things in the NetworkModule that I think are work taking note of

  • provideOkHttpInterceptors(): Sets up HTTP logging. This will allow us to monitor network requests and responses. It will only log when running the Debug version.
  • okHttpClient(): Sets up OkHttp client with some custom configs.e.g Adding HTTP logger, set timeout & read duration and custom interceptor that adds TMDB API key to requests.
  • provideRetrofitClient() : Sets up Retrofit client.

AppModule

Now that we have the Network module created, we can create an app module that will now ensure we have a singleton for our API service interface. If you’ve not used Retrofit, the interface defines API endpoints. It simply looks like this.

Here’s how the NetworkModule looks like. We’ve added the NetworkModule and ViewModelModule to the AppModule.

Note:
The method names for the providers, such as provideTmdbService()provideRetrofitClient(), are not important and can be named anything you like. Dagger only looks at the return type.

Create Components

We only have one component at the moment AppComponent.

We’ve specified the modules we want to be used with the component inside the @Component annotation.

Boom. We are done setting up our dagger. ?

Let The @Injection Begin

Now that we have all our dependencies set up, let’s use them.

1. Application Class

We need to initialize the dependency graph for our application by using the Component. This is pretty simple in Dagger 2.

AppInjector.init(this);

Don’t forget to add property android:name=".TmdbApp" to the tag in AndroidManifest.xml file.

2. TmdbRepository Class

I’ve created a class TmdbRepository in the repository package that is responsible for making API requests and returning data to our ViewModels.

We’ve used @Inject annotation on TmdbRepository constructor which in turn tells Dagger that to use the constructor to create an instance of TmdbService. This adds this class to the Dependency Graph.

3. MainActivityViewModel Class

As discussed earlier, using @Inject annotation on MainActivityViewModel constructor which in turn tells Dagger that to use the constructor to create an instance of TmdbRepository.

By doing so, the ViewModel does not care how we get out data. It just wants data from our repository.

4. ProjectViewModelFactory Class

ProjectViewModelFactory implements ViewModelProvider.Factory. This class is responsible for instantiating our ViewModel classes.

5. MainActivity Class

We can now use load data in our MainActivity. We call getPopularMovies() which will return some data. We then use observe which will listen for any changes to our data.

This is how the entire code looks like.

Wrapping it up

You can download the final project on Github

Dagger can be a bit of a pain when starting but don’t let it get to you. Dependency injection becomes useful when implementing proper testing into your app, allowing mock implementations of back-end APIs and data repositories to be used in testing.

There’s much more to learn about in Dagger 2 and its usage, including:

  • Scopes
  • Subcomponents
  • Testing with Mockito

In the next series, well look at setting up the UI and maybe writing some tests. In the meantime, happy injecting.

References

  1. Vogella – Dependency  Injection
  2. YouTube video by Gregory Kick: DAGGER 2 – A New Type of dependency injection
  3. YouTube video on DI by Dan Lew: Dependency Injection made simple
  4. Dagger 2: official page
  5. Codepath: tutorial on Dagger 2

 

 

Android Integration Testing

If it’s not tested, don’t trust it.

 

If you are building software, you have to test it. If it isn’t tested then I promise it will fail in some horrible way. I learnt this the hard way and trust me it wasn’t fun. Staying up late, debugging code only to find out your endpoint has a hyphen or you were incrementing a variable by itself and now one.

You end up wanting to shoot yourself.

After learning to appreciate tests, I end up catching some of these silly mistakes and saving time. You end up finding bugs before your customers do. Trust me, you don’t want bad reviews.

Introduction

By creating and running  tests against your code, you can easily verify that the logic of individual units is correct. Running unit tests after every build helps you to quickly catch and fix software regressions introduced by code changes to your app.

There are two main types of tests:

  1. Local Unit Tests: These tests run on the local JVM and do not have access to functional Android framework APIs. They don’t rely on the Android framework.
  2. Instrumented Tests: These are all tests that must run on an Android hardware device or an Android emulator. They are used to mock the actual behavior of the app. Eg storing data in SQL or UI elements.

For more info check out Android’s training guide.

In this tutorial, we’ll focus on Integration Testing, testing our endpoints ensuring we get the right response.

Enough talk. Let’s get this party started.

Prerequisites

  1. TMDB Api Key: You’ll need to get an API key to be able to test this out.  Get your API key here.

If you are new to Retrofit, you might want to read this. I’ve been using this library for all my network call.

Package Structure

Screen Shot 2016-08-30 at 2.27.23 PM

  1. Api Package: Contains classes that do all the api work, setting up the interface and retrofit object.
  2. Model: Contains Java classes need for capturing the JSON output. I use  and using jsonschema2pojo to help me generate my classes.
  3. Util: Contains class utilities. Right now it only contains a class with constants used across the app.

Creating the Retrofit instance

To send out network requests to an API, we need to use the Retrofit builder class and specify the base URL for the service.

 

Create an Interceptor

When making any API request to TMDB, we require the API key. To do so, we create a class that extends Interceptor and add that to OkHttpClient .addInterceptor(). This will ensure that all requests are added to the request.

Define the Endpoints

With Retrofit 2, endpoints are defined inside of an interface using special retrofit annotations to encode details about the parameters and request method.

  We are now ready to test the our enpoints. telegram-i-migliori-stickers-da-aggiungere-alla-vostra-collezione-3

Testing the Endpoints

Unit Tests are in src/test/java. We’ll create a class which will have all your test. 1. Create an instance of the request object Call topRatedList = getTmdbApiClient().movieInterface().getTopRatedMovies(); 2. User Response to execute the request

Response movieResponse = topRatedList.execute();

Run Your Test

If all goes well all your tests should pass.

All Test Results

Touch down

That’s it. I now trust my endpoints and and so can you.

In the next post, I will show you how to test UI functionality. We will build on the same app.

Go yee and test your endpoints!
jesus_ok___telegram_sticker_by_jinkazama84-d8qqmqi

The code is available on Github. Instructions on where to put the API key are in the README file.