Loading data from given api and showing them in a list.
Implement a map Activity/Fragment with Google Maps. Show all available vehicles on the map. Use the bounds of the map to request the vehicles. The map should zoom in and center on a specific vehicle when it is selected in the previously implemented list.
The project is structured following the guideline of [Android Architecture Components].
The ui
package contains activity
and fragments
which renders the data on the screen and viewModel
is used to contain and manage the state.
Additionally there are vo
and adapter
packages which contain ViewObject
and adapters
.
The repositories
and data
packages are part of the data layer where repositories
handle the business logic.
The data
package contains retrofit
client for API calls and room
for local data storage and sync.
To manage dependencies between components dagger-hilt
is used and the module is kept in di
package
other
package contains the followings
- ConnectivityObserver helps to observe connectivity
- BitmapHelper helps to draw marker from vector drawable
- Constants constant object/values
- Ext extension functions or helper functions
Clean
architecture andSOLID
principle has been strictly maintain during the process of the development.Unit Test
,Integration Test
andE2E Testing
has also been respectively implemented.
In MainActivity [Navigation Component] is used to host all the fragments
in the NavHostFragment
.
A [Bottom Navigation View] is implemented so that user can easily navigate between fragments
.
[Dagger-hilt] is used for dependency injection.
Turbine is used to test flow and Truth for easy assertion in unit tests.
Retrofit is used for API services and Room for storing and managing data locally.
api is implemented in VehicleApi.
Here, we have a JSON as API response which contains a list of vehicle information (id, coordinate, fleetType, state and heading)
In the VehiclesFragment, list of all available vehicles as SingleVehicle is shown. Each list item contains the value of type
, address-line
and state
GeoCoder is used to convert all Coordinate
from VehicleData into address-line
The API often returns 100 or more vehicle information, hence, paging-3 is used to slow loading the items in the list and provide a better user experience.
VehicleDao provides access to VehicleDB
which is used to store all new data from the list or update if a change occurs in the existing vehicle data.
When the app is live, it will request api every 20 seconds using coroutine's Dispatchers.IO
context.
[Kotlin Flow] is used for data streaming. Hence, with the change syncing in vehicles
table, paging-3
library have PagingSource
API which maps data from Flow
and stream it to VehicleRecyclerViewAdapter which is a PagingDataAdapter
VehicleListViewModel holds the state of all the data so that the list page survives the configuration changes.
In the MapFragment all vehicle is shown as markers. Here, a carIcon
is represented as custom marker which is created using bitmap-helper.
Response from the VehicleApi is fetched and mapped into List
of VehicleMarker which is set on the map as markers according to their LatLng
.
All the basic gestures(e.g., zoom, pan) are enabled in the map. When a SingleVehicle is selected from VehiclesFragment, MapFragment opens and zoom in towards the selected VehicleMarker.
MarkerInfoWindowAdapter is used to show the details of a marker in the map when tapped.
It occurred to me that the VehicleApi response is always changing. Hence, I developed VehicleDataSource to load data from API
and then sync with VehicleDB.
Upon receiving data from API
the app is deleting all vehicle information that are not in the latest data set. Then, it updates any existing vehicle information and add new vehicle information in VerhiclrDB
.
DELETE FROM vehicles WHERE vehicleId NOT IN (:list)
is the query to delete all vehicle information not in the latest data set.
VehicleDataSource
repeats the whole process every 20 seconds in a Dispatchers.IO
coroutine context.
This enables zero loading time and a very neat user experience.
- Google Maps SDK for Android for map and marker
- Android Support Library
- Android Architecture Components for MVVM and clean architecture
- Bottom Navigation View for bottom menu
- Navigation Components for hosting fragments
- Jetpack Paging Library for loading data in recycler view
- Kotlin Flow for asynchronous data transfer
- Retrofit for REST api communication
- Room DB for local storage and caching
- Dagger-hilt for dependency injection
- SDP for dynamic size unit
- Truth for Unit tests assertion
- Turbine for testing flow
- espresso for UI tests
- GeoCoder for getting address from coordinates