Remote API
Connecting to the Internet
Permissions
- Go to app -> manifests, and add
<!-- Declare permission -->
<uses-permission android:name="android.permission.INTERNET" />
<application></application>
-
Retrofit: Retrofit is a type-safe HTTP client for Android, developed by Square. This is industry standard and recommended by Google.
- GET: Retrieve data from the server.
- POST: Create a new resource or submit data.
- PUT: Update or replace an existing resource.
- DELETE: Remove a resource.
- Typical JSON API
- https://my-json-server.typicode.com/GithubGenericUsername/find-your-pet/contacts
- https://my-json-server.typicode.com/GithubGenericUsername/find-your-pet/contacts/4
- Go to Gradle script and add dependency
in Geadle script (module)
// on the top
plugins {
// ...
id("org.jetbrains.kotlin.plugin.serialization") version "2.2.21"
}
// at the bottom
dependencies {
// room setup
// ...
// retrofit
val retrofit_version = "3.0.0"
implementation("com.squareup.retrofit2:converter-kotlinx-serialization:$retrofit_version")
implementation("com.squareup.retrofit2:retrofit:$retrofit_version")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0")
}
- Create a new package under the main pacakage called remote and under the package create a new kotlin class called ContactDto.kt
package at.uastw.contactsapp.remote
import kotlinx.serialization.Serializable
@Serializable
data class ContactDto (
val id: Int,
val name: String,
val telephoneNumber: Int,
val age: Int
)
- Create an interface under remote called ContactRemoteService.kt
in ContactRemoteService.kt
package at.uastw.contactsapp.remote
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Path
interface ContactRemoteService {
@GET("contacts")
suspend fun getAllContacts(): List<ContactDto>
@GET("contacts/{contactId}")
suspend fun getAllContactById(@Path("contactId") id: Int): ContactDto
@POST("contacts")
suspend fun addContact(@Body contactDto: ContactDto)
}
in ContactRepository.kt
// update
// class ContactRepository(private val contactsDao: ContactsDao) {...}
class ContactRepository(
private val contactsDao: ContactsDao,
private val contactRemoteService: ContactRemoteService
) {
// newly add on top
suspend fun loadInitialContacts(){
Log.w("REPOSITORY", "Start loading")
val remoteContacts = contactRemoteService.getAllContacts()
Log.w("REPOSITORY", "Done loading")
// map the data from the Internet to our database
remoteContacts.map{
dto ->
ContactEntity(0,dto.name, dto.telephoneNumber.toString(),dto.age,)
}.forEach{
entity -> contactsDao.addContact(entity)
}
}
// ...
}
- Until here, if we run the app, it will crash because ContactRepository(contactsDao) in ContactsApplication.kt is not correct.
in ContactsApplication.kt
class ContactsApplication : Application() { // only one instance
// by lazy: only execute this code once, once it is accessed somewhere
val contactRepository by lazy {
val contactsDao = ContactsDatabase.getDatabase(this).contactsDao()
// setup a retrofit service
val retrofit = Retrofit.Builder()
.baseUrl("https://my-json-server.typicode.com/GithubGenericUsername/find-your-pet/")
// without contacts because we added it in the ContactRemoteService
.addConverterFactory(Json { ignoreUnknownKeys = true }.asConverterFactory("application/json".toMediaType()))
// do the serialization
.build()
// Create an object for us that implements this interface
val contactRemoteService = retrofit.create(ContactRemoteService::class.java)
ContactRepository(contactsDao, contactRemoteService)
}
}
- Now we need to use this loadInitialContacts() in the ContactsViewModel
in ContactsViewModel.kt
val contactsUiState = repository.contacts.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(5000),
// when it should start the state, and how long it should keep it
// it will remain 5 sec after the viewmodel scope is closed
emptyList() // Define the initial value
)
// newly add
// only call for the first time
init {
viewModelScope.launch {
repository.loadInitialContacts()
}
}
Until now, the json file should be appended after the existing data.
Potential errors
- apk-build-fails-with-error-failed-to-open-apk-inconsistent-information: Solution: File -> Invalidate caches & restart This is because Android Studio may keep some information to speed up the build process.
Terminology
-
API: An application programming interface (API) is a connection between computers or between computer programs. It is a type of software interface.
-
Data Transfer Object (DTO): DTOs are a crucial design pattern used to effectively transmit data from one layer to another while keeping the required data pieces in a lightweight structure.
Reflection
- One can move database package and remote package under the data pacakage