androidkotlinandroid-listviewretrofit

Retrofit API call returning NULL data


I am calling an API using retrofit and the it is returning null.

Model class

data class Employee(
    val id: Int,
    val employee_name: String,
    val employee_salary: Int,
    val employee_age: Int,
    val profile_image: String
)

ViewModel class

package com.example.myproject.ViewModel

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.myproject.Service.ApiService
import com.example.myproject.model.Employee
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

class EmployeeViewModel : ViewModel() {

    private val _data = MutableStateFlow<List<Employee>?>(emptyList())
    val data: StateFlow<List<Employee>?> = _data
    init {
        fetchData()
    }
    private fun fetchData() {
        viewModelScope.launch {
            try {
                val apiService = Retrofit.Builder()
                    .baseUrl("https://dummy.restapiexample.com/")
                    .addConverterFactory(GsonConverterFactory.create())
                    .build()
                    .create(ApiService::class.java)
                val response = apiService.getEmployees()
                _data.value = response
            } catch (e: Exception) {
                // Handle error
                // _data.value = emptyList()
                e.printStackTrace()
            }
        }
    }
}

Api service interface

interface ApiService {
    @GET("/api/v1/employees")
    suspend fun getEmployees(): List<Employee>
}

MainActivity.kt

package com.example.myproject

import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Card
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import com.example.myproject.ui.theme.MyProjectTheme
import androidx.lifecycle.viewmodel.compose.viewModel
import com.example.myproject.ViewModel.EmployeeViewModel
import com.example.myproject.model.Employee

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyProjectTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    val viewModel: EmployeeViewModel = viewModel()
                    EmployeeScreen(viewModel)
                }
            }
        }
    }
    @Composable
    fun EmployeeScreen(viewModel: EmployeeViewModel) {
        val data by viewModel.data.collectAsState(initial = emptyList())

        if (data?.isEmpty() == true) {
           CircularProgressIndicator()
        } else {
            LazyColumn {
                items(data!!) { employee ->
                    EmployeeListItem(employee)
                }
            }
        }
    }

    @Composable
    fun EmployeeListItem(employee: Employee) {
        Card {
            Column {
                Text(text = employee.employee_name)
                Text(text = "Salary: ${employee.employee_salary}")
                Text(text = "Age: ${employee.employee_age}")
                // Add image view if profile_image is available
            }
        }
    }
}

It is returning me null data with no warning I have also added the appropriate dependencies for retrofit, gsonconverter and okhttp but still the response is blank. Help appreciated!


Solution

  • I believe, the thing is. That api does not just return a list of employees. You can check yourself at https://dummy.restapiexample.com/api/v1/employees . It returns an object with the fields status, data and message. That data is the list of employees. So you need a class that represents the full response. Like

    data class EmployeeResponse(
        val status: String,
        val data: List<Employee>,
        val message: String
    )
    

    And fix the interface to use this class

    interface ApiService {
        @GET("/api/v1/employees")
        suspend fun getEmployees(): EmployeeResponse
    }
    

    and

    _data.value = response.data