Hello.
The app is written in Kotlin with all the supported Unit and Instrumentation tests.
As such in this project i aim to demonstrate:
- Clean Architecture with MVVM (Model View ViewModel) on the presentation layer
- Use of Jetpack libraries
- Use of Kotlin's Coroutines and Flow for background execution
- Dependency Injection using Dagger Hilt
- Persistence with Datastore.
- Clean UI with material design.
- Finally it takes a sneak peak into github actions for autobuilds and ci using github actions
In order to run this project you need the following:
- Android Studio 4.1.1 or better
- Gradle 6.5 or better
- JDK 1.8
- Android SDK
Its practically improbable to have it all in order, as disorder is the natural state of order. However in this project i tried keep a distinct separation of concerns, that in turn brings a level of structural sanity to the codebase. As shown in the pictorial illustration of clean architecture, this app is divided into three sub modules - Domain, Data and App.
The domain layer contains UseCase / Interactor instances that are used to collect data from the Data Layer and pass it to the Presentation Layer (App). As such in our context we have only one UseCase GetForecast
. This layer does not have any mapper classes.
All the interfaces to be used in the data layer were defined here, also in accordance with the DIP principle, this is to make sure that all the modules depend on abstractions.
The data layer is responsible for the data that will be fed to the entire application, in our case we had to fetch data from a remote source and display it to the user (open weather). As an agreement to the contract shared by the domain layer, concrete classes implementing the interfaces reside in this layer. With the aid of mapping we are able to have an exchange in abstractions between the two layers.
The networking here is performed by Retrofit
. A popular Http client for android. Retrofit depends on OkHttp
to make requests.
Retrofit
also has builtin support for Coroutines
hence my choice in the library. Persistence is to be achieved via room
This layer has houses all Android Framework specific tooling i.e User Interface (UI) and ViewModels
which bridge the gap between the data abstractions and the UI. The architecture used in this layer was MVVM as it gives a good separation of concerns. The availability of lifecycle aware components also made the decision to go with MVVM an easy one to make. The ViewModels contain a reference to UseCase
instances, these references are passed through dependency injection.
Data binding
this is an amazing tool, using binding adapters reduces a lot of boiler plate, thus making views cleaner.
LiveData
keeps you updated all the time.
Dagger Hilt
Simple dependency management.
Timber
for logging
Retrofit and okhttp
for api calls
Wakatime
for time tracking
Unit Tests are available for each layer and Instrumentation tests are present in the presentation layer. I tried to cover as much as i can, but i think there could still be room for more.
With the aid of the debounce operator, whenever a user types into the search field, it waits for 500ms before making a request.
Room caching could be a good idea, i will add it as soon as i get the time.
- Kotlin
- Kotlin Coroutines
- Flow
- Retrofit - An http client for android
- Okhttp - For networking requests
- Mockito - For mocking instances
- Dagger Hilt - For dependency injection
- Truth - For assertions during testing
- Jetpack Libraries
- Roboelectric - To enable me to run android tests on the JVM. This potentially reduces testing time
From a standard device - Galaxy Note 9
With the help of wakatime, this project took approximately 12 hours over a span of 14 days.
I didn't implement offline caching because of the additional feature of search as you type that was implemented. Using this specific implementation in an offline setup would have required me to download as much data as i can, so that when there is no connection the user can always retrieve the forecast from the local db.