This is a simple Android app written in Kotlin that displays the current weather for a input location.
Here Destination Weather API is used to fetch the current weather information
- Android Architecture Components for easy MVVM implementation
- Material Components for beautiful Material UI
- Timber for logging
- Retrofit for REST communication (duh)
- Moshi for Kotlin-friendly deserialization
- Koin for dead-simple Dependency Injection
- Lottie for smooth weather animations
- Coil for modern network Image fetching using Kotlin coroutines
- Mockk for Kotlin-friendly mocking in unit tests
This app follows Clean architecture by Uncle Bob
The code is divided into 3 main layers: Data, Domain, and Presentation
The Data layer is responsible for fetching data from the API and supplying it to the Domain layer.
Retrofit is used with Moshi to fetch and deserialize the response from the API. A set of response objects (DTOs) are included in this layer. They map 1-1 to the API contract
A OkHttp Interceptor handles authentication with a simple API Key-based system.
OAuth2.0 could be a future improvement
A simple in-memory repository is used for holding the data returned by the API.
The repository supports synchronous and asynchronous fetching, as well as refreshing from the API.
A simple Mapper
class is used to map from the response objects (DTOs) to the domain entities
The domain layer is responsible for handling data flow and business logic
A set of Entities
are used in this layer. These models more accurately map to the app business requirements
UseCase
s are included in this layer. They use a suspend function to allow the presentation layer to interface via Kotlin coroutines
The presentation layer is responsible for displaying the data returned from the Domain layer to the user.
The MVVM pattern is used here to divide the UI logic from the Android framework. The View
(Activity currently) is designed to be as "dumb" as possible.
The ViewModel exposes a UiState
LiveData stream that continually emits based on external events like user input and network responses. The UiState should be a nearly direct representation of the UI on the screen. Some "sub-UiStates" were created to standardize this approach (ImageUiState, AnimationUiState, TextInputUiState). This approach was inspired by Jetpack Compose
viewModelScope
CoroutineScope is used to easily handle cancelling network calls based on the Android Activity lifecycle
DataBinding is leveraged to minimize logic and boilerplate in the View. Most data from the ViewModel's UiState is directly mapped to the Android View
s
Some animations were added using Lottie to portray the current weather conditions. A small set of animations were added; this could be expanded to include all possible weather conditions
To view the various animations available, pull out the debug drawer from the very left side of the screen
Github Actions is used to build and run unit tests on each commit on the master
branch
See this build for an example https://github.com/mrea1/WeatherApp/runs/862106667
Future enhancements could include:
- Continuous Delivery (CD) using a framework like Firebase App Distribution or HockeyApp (now Visual Studio App Center)
- Automated UI testing using a framework like Waldo or Appium
A small set of unit tests are included. The architecture in the app allows for easy unit testing.
JUnit 4 is used currently. A future improvement could be to use JUnit 5.
Mockk is used to mock dependencies in unit tests. It works well with coroutines, in contrast to Mockito
UI testing with Espresso is not really needed here, since the bulk of UI logic is easily unit tested on the ViewModel layer