Basic MVVM Android App
Table of contents
About App
We are building a simple MVVM (Model View View-Model) app which is using Rick and Morty API.
Basically we are separting our concerns.
lets say we want to change request method from GET to POST, we only have made changes in Network Layer.
- First read the Rick and Morty Documentation
Retrofit
Retrofit is a type-safe REST client for Android and Java which aims to make it easier to consume RESTful web services.
First, create a Retrofit Service
It defines how the app should talk to the server, in our case we are sending a GET request.
interface RickAndMortyService { @GET("character/{character-id}") suspend fun getCharacterById(@Path(value = "character-id") characterId: Int): Response<GetCharacterByIdResponse> }
Network layer
First, create a Moshi object to parse JSON
Create a Retrofit Object
create a Retrofit Service using our Service Interface
finally, create an API client that which app can use to talk to the API using the Retrofit service.
object NetworkLayer {
// Moshi to parse JSON into Java and Kotlin classes:
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
val retrofit: Retrofit = Retrofit.Builder()
.baseUrl("https://rickandmortyapi.com/api/")
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
val rickAndMortyService: RickAndMortyService by lazy {
retrofit.create(com.example.rickmorty.RickAndMortyService::class.java)
}
val apiClient = ApiClient(rickAndMortyService)
}
Create API Client
- It has a method to retrieve the response from API.
class ApiClient(private val rickAndMortyService: RickAndMortyService) {
suspend fun getCharacterById(characterId: Int): Response<GetCharacterByIdResponse> {
return rickAndMortyService.getCharacterById(characterId)
}
}
Repository
It has the logic to send a request to API and retrieve a response using Network Layer via the API client.
class SharedRepository {
suspend fun getCharacterById(characterId: Int): GetCharacterByIdResponse? {
val request = NetworkLayer.apiClient.getCharacterById(characterId)
if (request.isSuccessful) {
return request.body()
}
return null
}
}
ViewModel
ViewModel business logic or screen level state holder, which has the state of the UI and it exposes the state to UI and listens for changes.
class SharedViewModel : ViewModel() {
private val repository = SharedRepository()
// to store retrieved data
private val _characterByIdLiveData = MutableLiveData<GetCharacterByIdResponse?>()
val characterByIdLiveData: LiveData<GetCharacterByIdResponse?> = _characterByIdLiveData
fun refreshCharacter(characterId: Int) {
viewModelScope.launch {
val response = repository.getCharacterById(characterId)
_characterByIdLiveData.postValue(response)
}
}
}
- Use the LiveData variable to store the response as it is an Observable Data holder class and the observer will be notified when data changes.
Activity (UI)
Here we will observe the response stored in the LiveData object from ViewModel
viewModel.characterByIdLiveData.observe(this)
// action to take while observing
}
Here is the Github Repository
Subscribe to my newsletter
Read articles from Harish Sheoran directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Harish Sheoran
Harish Sheoran
DevOps Engineer