An android application built with Jetpack Compose, consuming the Countries API to display countries and details about them . Credits to HNGi9.
- Smooth display of Countries from the
API
- View Country's Details on click.
- Network Error Handling
- Search Country By Name
- Filter countries by:
- Currency
- Sub-region
- Region
- Capital
- Language
- Enable Localization,i.e read data using any language
Being an application handling a lot of data, the project strucure is divided into multiple packages to separate concerns hence making it easier to read, scale and update. The layers include:
It contains a repository
that ONLY has function definitions. The functions are what the API should do ONLY not how to do it. For example, suspend fun getCountries(): List<CountryResponseItem>
It contains the data from the Country API. The data is represented in form of a JSON object.
To transform the JSON to Kotlin objects that can be understood by the compiler, a tool is used.
The tool name is JSONtoKotlinClass. This generates Kotlin objects automatically from JSON objects and is obviously faster than manual coding of the Kotlin Objects.
However, not all Kotlin objects from the endpoint are needed in the application, therefore a custom model class is manually created to represent objects that will be presented in the screens.
In the CountryResponseItem
an extension function is created to return objects of the custom model class.
It also contains the routes to be accessed by the API during execution in the CountryApi
It also use_cases
classes.
Each class has only one public function,i.e to execute the use case function
- It is useful within a class having a single method
- Specifying an invoke operator on a class allows it to be called/executed on any instances of the class without a method name.
- The return type of the function is Flow -> emit multiple values over a period time, i.e wrapped in the Resource(Success/Error/Loading)
- e.g -if an error occurs, it will be emitted here,
-
-if a success occurs, attach the data fetched(List of Countries) and emit it
- HttpException- what to do in case of error/ Http codes except those starting with 2 (successes)
- IOException - what to do if the api can't connect to the remote server e.g when device isn't connected to the internet
Lastly, the data layer contains the implementations of the repository defined in the domain layer.
It contains functions that create dependencies.
This contains the screens to be displayed as well as the logic used to display the screen, e.g viewmodel
and state management.
- Retrofit - This is a type-safe client for Android which makes it easier to consume RESTful web services/ connect to the network.
- Moshi Converter - This helps in serialization and deserialization of code. The
generateAdter = true
helps in creating an adapter for the data classes generated. The codegen is used since if not employed Moshi works by coincidence with just standard Java reflection which is error prone. Therefore, in codegen, the generated adapters are Kotlin themselves which are fast. Codegen allows generating code at compile time, so they can perform serialization and deserialization using reflection, that is why it is fast. - Coroutines - This helps in writing asynchronous code, therefore allowing heavy operations , e.g fetching data from API to be done on a background thread avoiding screen lag.
- Navigation - This enables moving from one screen to the next.
- Coil - This helps in image loading from the network.
- Hilt - It is a library for Android that reduces the boilerplate of using manual DI in your project. It decouples code and makes it easier to test in future.
- The previous version had generated too many and unnecessary model classes. That made the runtime longer and complex to work with in the UI layer. For example, the
Currency
details could only be displayed as an object in the screen, i.e.Currency: Dollar(name= Dollar, symbol = $)
. - Through further consultation, the API was discovered to be inconsistent. It will give different results for different request. Normally, a consistent API would return the same result for different requests, e.g different
names
should return aString
. Due to the inconsistency, the JsonToKotlin Plugin would generate numerous(400+) data classes. - Personally, I tried tweaking with the generated model to give better UI but it led to
ClassCastException
.That is changing Dollar to a data class with name and symbol as parameters. - To overcome this, data from the endpoint had to be fetched manually by inferring the inconsistent responses. E.g.
val currencies: Currencies?
changed toval currencies: Map<String, Currencies?>
. The type inferred should be similar to the JSON response otherwise it would cause avoidable pain e.g.List<Currencies?>
would cause an error. - In future, one can watch out for such anomalies in the endpoints by using Postman to test the API. Alternatively, go through the API documentation to see for yourself.
The application is still a work in progress and will add the respective features as time goes by. Run the following links, preferrably the latest, and feel free to clone and adjust the applications to your liking.
- Second Submission Appetize Link V.0.0.0
- First Submission. Appetize Link v.1.0.0