The application contains the following functionalities:
- Fetch user data from https://randomuser.me/
- Display a list of users, with each item containing the user's name, email, and picture
- As the user scrolls, load additional users
- When offline, the user should be able to see the previously loaded users from the last time they were connected
- When there is an error fetching additional users, display an error message to the user
- When the API returns an empty result, display an empty screen state
- Download the latest stable Android Studio
- Import the project
- Run the app
To execute the unit tests report run:
./gradlew test
To generate the test coverage report run:
./gradlew koverHtmlReportDebug
The report will be generated in app/build/reports/kover/htmlDebug/index.html
To execute the instrumented tests report run:
./gradlew connectedAndroidTest
Use the emulator to test.
The report will be generated in app/build/reports/androidTests/connected/debug/index.html
The application architecture has three layers: data layer, domain layer, and UI layer.
The architecture follows a reactive programming model with unidirectional data flow. With the data layer at the bottom, the key concepts are:
- Higher layers react to changes in lower layers.
- Events flow down.
- Data flows up.
The UI Layer is structured using the MVVM (Model-View-ViewModel architectural design pattern which allows better code separation, testability, reusability and maintainability of UI logic and UI components.
The data layer and domain layer are structured using the Clean Architecture for better readability, maintainability, testability, adaptability, and clear separation of concerns. Making it easier to modify or extend the application without affecting its core functionality.
The application make heavy of use the S.O.L.I.D principles.
- All architectural layers use dependency inversion
- Classes have a single responsibility
- Classes are focused on extensibility
- Interfaces have a clear purpose and are implemented by its intended classes.
To achieve the offline functionality it was used the Single source of truth (SSOT) pattern. Where the data is converged and normalized into the local database which is consumed by the application in order to display data reliably.
When the user opens the app or scrolls the user list, the app will attempt to load the first page of users from the remote server. If successful, the data will be stored into the Room database and displayed to the user. In case the user tries load more data and the request fails or the device doesn't have an internet connection, the application will return the last previously stored user data from the database.
The following diagram shows the events which occur and how data flows from the relevant objects to achieve this: