Simple weather forecast app using Kotlin, Retrofit and RxJava2

Konrad Szewczuk
AndroidPub
Published in
4 min readJan 14, 2018

--

In the last weekend I decided to dive more into Kotlin and fetching data from web API using RxJava2 and Retrofit. The app will get basic info about current weather and also for weather for next hours and days in a week. In the end of this article I provided the link to the full app source code on Github.

The tools I decided to use were:

  • Kotlin
  • Retrofit 2
  • RxJava and reactive libraries like RxBinding, ReactiveNetwork, RxAndroid
  • Android Architecture Components(Room, ViewModel)
  • Dagger2
  • Some libraries like MPAndroid chart
  • Also Mockito for writing tests

I decided to use Dark Sky API to get weather data.

Here is how the Retrofit interface looks like:

So, in the UI the user should get the current weather by providing the city name. In this case we need to map this name to actual latitude and longitude.

This can be achived by using Geocoder, but i decided to use its API directly by Retrofit. This information will be fetched and then pass to our RemoteWeatherService(just for fun ✌️)

Here is how the interface for fetching location by name will look like:

The full endpoints for both services can be seen on the API documentations.

So we have two services, which will fetch Single. It is good to have Single instead of Observable, because we need to get only one item and this should be finited action(not like we will be waiting for other events).

Next, we need to combine the results of those two. As we know, the RemoteWeatherService is depended on RemoteLocationService, we need to know the location first to fetch weather for specific place.

To perform this action we will use some repository, which will deliver the combined result.

Here is how we can combine those two Single:

As we can see wee need to provide dependencies to this repository. This can be achived with Dagger using constructor injection.

Again, our aim is to combine those to method request to get the one DTO(Data-Transfer-Object). So the getWeather method is performing the first call and when we gather its response(in this case this will be the LocationResponse object)it is flatMapped with another call, which will fetch the WeatherReponse object. With combining those two objects we can create the WeatherDetailsDTO object which we can pass to the upper layer of our application. In this case, this will be the ViewModel.

WeatherViewModel can have the reference to this WeatherRepository(actually, the WeatherRepository is just an interface, WeatherViewModel really don’t need to know about the actual implentation). So WeatherViewModel can have method like this:

For this case ViewModel is just an another abstraction, which is useful for testing and clean code. It shares this DTO object to whatever View that subscribes to the getWeather method.

Now, we can subscribe to this method from our Activty and do whatever we want with this WeatherDetailsDTO object. Let’s take a look on example:

We can invoke this method in our activity, and fetch the wanted weather info. Of course, we should manage our Disposable and add it to some CompositeDisposable. We can get the input from some EditText:

So this was the basic flow of the app. There are others functionality with very similiar flow, but also with the Room database layer instead of the web API. Again, in this case the WeatherRepository can combine the data from Room or web API and then pass it to the ViewModel. ViewModel doesn’t need to know if the data was from Room database or from internet.

Lastly, let’s take a look on some tests. First here is how the basic getWeather from WeatherRepository can look like:

We mocked the behaviour of our Retrofit API services, which in this test will return some prepared mock object for LocationResponse and the WeatherResponse. Then we are invoking our method which should return the combined object from those two calls. We also check if there was an interaction with RemoteWeatherService after the LocationWeatherService request has ended successfully with LocationResponse. For this, we can use the ArgumentCaptor which can be used to get the argument passed as an parameter in between our test.

In the end, let’s take a look on ViewModel basic test.

Again, we are using Mockito.verify() method with ArgumentCaptor to check if there is an interaction between ViewModel and WeatherRepository with expected method arguments.

So thats it. You can see much more in the whole source code of the app which can be found here:

I hope this can be helpful for you. If you liked this article, don’t forget to 👏 ! It will give me some motivation to make more :)

Cheers!

--

--