Skip to main content

Api Call with Mvvm+JetPackCompose Kotlin

 Add Important Dependency

alias(libs.plugins.compose.compiler)
id("org.jetbrains.kotlin.plugin.serialization") version "2.0.0"

alias(libs.plugins.compose.compiler) apply false

buildFeatures {
dataBinding = true
viewBinding = true
compose=true
}

compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }

//jetpack compose dependency
dependencies {

val composeBom = platform("androidx.compose:compose-bom:2024.10.01")
implementation(composeBom)
androidTestImplementation(composeBom)

// Choose one of the following:
// Material Design 3
implementation("androidx.compose.material3:material3")
// or Material Design 2
implementation("androidx.compose.material:material")
// or skip Material Design and build directly on top of foundational components
implementation("androidx.compose.foundation:foundation")
// or only import the main APIs for the underlying toolkit systems,
// such as input and measurement/layout
implementation("androidx.compose.ui:ui")

// Android Studio Preview support
implementation("androidx.compose.ui:ui-tooling-preview")
debugImplementation("androidx.compose.ui:ui-tooling")

// UI Tests
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-test-manifest")

// Optional - Included automatically by material, only add when you need
// the icons but not the material library (e.g. when using Material3 or a
// custom design system based on Foundation)
implementation("androidx.compose.material:material-icons-core")
// Optional - Add full set of material icons
implementation("androidx.compose.material:material-icons-extended")
// Optional - Add window size utils
implementation("androidx.compose.material3.adaptive:adaptive")

// Optional - Integration with activities
implementation("androidx.activity:activity-compose:1.9.2")
// Optional - Integration with ViewModels
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5")
// Optional - Integration with LiveData
implementation("androidx.compose.runtime:runtime-livedata")
// Optional - Integration with RxJava
implementation("androidx.compose.runtime:runtime-rxjava2")

}



//retrofit dependency
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")

//coroutines dependency
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9")

// Kotlin Serialization Core
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")

// Retrofit Kotlin Serialization Converter
implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0")

Create ApiService




interface ApiService {

@POST("User/SurveyPropertyRegistration")
suspend fun propertyRegistration(@Body propertyRegistrationRequestModel: PropertyRegistrationRequestModel): Response<PropertyRegistrationResponseModel>

@POST("User/PropertyReport")
suspend fun propertyDetailsList(): Response<PropertyDetailsListResponseModel>

@POST("User/SurveyPropertyRegistration")
suspend fun propertyRegistrationJetWay(@Body propertyRegistrationRequestModel: PropertyRegistrationRequestModel): PropertyRegistrationResponseModel

}



Create RetrofitInstance

object RetrofitInstance {
private const val BASE_URL = "https://api.assignhealthcare.in/api/"
val apiService: ApiService by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(
OkHttpClient.Builder()
.connectTimeout(120, TimeUnit.SECONDS)
.readTimeout(120, TimeUnit.SECONDS)
.writeTimeout(120, TimeUnit.SECONDS)
.addInterceptor { chain ->
try {
chain.proceed(chain.request())
} catch (e: SocketTimeoutException) {
throw e
}
}
.build()
)
.build()
.create(ApiService::class.java)
}
}



Create DataRepository

class DataRepository(private val apiService: ApiService) {

suspend fun propertyRegistration(propertyRegistrationRequestModel: PropertyRegistrationRequestModel): Result<PropertyRegistrationResponseModel?> {
return try {
val response = apiService.propertyRegistration(propertyRegistrationRequestModel)
if (response.isSuccessful) {
Result.success(response.body())
} else {
Result.failure(Exception("failure: ${response.code()} - ${response.message()} - ${response.errorBody()} - ${response.raw()}- ${response.headers()}"))
}
} catch (e: Exception) {
Result.failure(e)
}
}

suspend fun propertyDetailsList(): Result<PropertyDetailsListResponseModel?> {
return try {
val response = apiService.propertyDetailsList()
if (response.isSuccessful) {
Result.success(response.body())
} else {
Result.failure(Exception("failure: ${response.code()} - ${response.message()} - ${response.errorBody()} - ${response.raw()}- ${response.headers()}"))
}
} catch (e: Exception) {
Result.failure(e)
}
}


suspend fun createUser(request: PropertyRegistrationRequestModel): PropertyRegistrationResponseModel {
return withContext(Dispatchers.IO) {
apiService.propertyRegistrationJetWay(request)
}
}
}



Create MainViewModel

class MainViewModel(private val dataRepository: DataRepository) : ViewModel() {

private val mLiveDataPropertyRegistration =
MutableLiveData<Result<PropertyRegistrationResponseModel?>>()
val propertyRegistrationLiveData: LiveData<Result<PropertyRegistrationResponseModel?>> get() = mLiveDataPropertyRegistration

fun fetchPropertyRegistration(propertyRegistrationRequestModel: PropertyRegistrationRequestModel) {
viewModelScope.launch {
mLiveDataPropertyRegistration.postValue(
dataRepository.propertyRegistration(
propertyRegistrationRequestModel
)
)
}
}

private val mLivePropertyDetailsList =
MutableLiveData<Result<PropertyDetailsListResponseModel?>>()
val propertyDetailsListLiveData: LiveData<Result<PropertyDetailsListResponseModel?>> get() = mLivePropertyDetailsList

fun fetchPropertyDetailsList() {
viewModelScope.launch {
mLivePropertyDetailsList.postValue(dataRepository.propertyDetailsList())
}
}

//another way
private val _userResponse = MutableLiveData<PropertyRegistrationResponseModel>()
val userResponse: LiveData<PropertyRegistrationResponseModel?> get() = _userResponse

private val _errorMessage = MutableLiveData<String>()
val errorMessage: LiveData<String> get() = _errorMessage

fun createUser(request: PropertyRegistrationRequestModel) {
viewModelScope.launch {
try {
_userResponse.postValue(dataRepository.createUser(request))
} catch (e: Exception) {
_errorMessage.value = e.localizedMessage ?: "An error occurred"
}
}
}

}


Create MainViewModelFactory

class MainViewModelFactory(private val dataRepository: DataRepository) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(MainViewModel::class.java))
@Suppress("UNCHECKED_CAST")
return MainViewModel(dataRepository) as T
throw IllegalArgumentException("Unknown ViewModel class")
}
}

How Call MainActivity



@Composable
private fun PropertyDetailListApiCall() {
Button(onClick = {
viewmodel.fetchPropertyDetailsList()
}, modifier = Modifier.padding(start = 30.dp)) { Text("Fetch Data") }

val property by viewmodel.propertyDetailsListLiveData.observeAsState()

property?.let { it ->
it.fold(
onSuccess = {
if (it != null) {
Toast.makeText(context, it.np.responseMessage, Toast.LENGTH_SHORT)
.show()
PropertyDetailsListLayout(it.np.responseData)
} else {
Toast.makeText(
context,
"failed to fetch Data Or nullable",
Toast.LENGTH_SHORT
)
.show()
}
},
onFailure = {
Toast.makeText(context, it.message, Toast.LENGTH_SHORT)
.show()
})

}

}

@Composable
fun CreateUserScreen() {
val viewModel: MainViewModel =
viewModel(factory = MainViewModelFactory(DataRepository(RetrofitInstance.apiService)))
viewModel.createUser( PropertyRegistrationRequestModel())

val userResponse by viewModel.userResponse.observeAsState()
val errorMessage by viewModel.errorMessage.observeAsState()

Button(onClick = {
userResponse?.let {
try {
Toast.makeText(this, it.np.responseMessage, Toast.LENGTH_SHORT).show()
} catch (e: Exception) {
Toast.makeText(this, e.stackTraceToString(), Toast.LENGTH_SHORT).show()
}
}
errorMessage?.let {
Toast.makeText(this, "Error: $it", Toast.LENGTH_SHORT).show()
}
}) {

Text("Button")

}

}


Comments

Popular posts from this blog

Dropdown with Spinner & AutoCompleteTextView

  < com.google.android.material.textfield.TextInputLayout style ="@style/Widget.Material3.TextInputLayout.OutlinedBox.ExposedDropdownMenu" android :layout_width ="match_parent" android :layout_height ="wrap_content" > < AutoCompleteTextView android :id ="@+id/autoCompleteTv" android :layout_width ="match_parent" android :layout_height ="wrap_content" android :inputType ="none" /> object AutoCompleteHelper { fun < T > initializeAutoCompleteTextView ( context : Context , autoCompleteTextView : AutoCompleteTextView , data : List < T >, displayFunction : ( T ) -> String , onItemSelectedListener : ( position : Int , selectedItem : T ) -> Unit ) { val adapter = ArrayAdapter( context , android. R . layout . simple_spinner_dropdown_item , data . map ( displayFunction )) autoCompleteTextView .setAdapter( a...