Home > Blockchain >  Retrofit after adding Flow does not return values
Retrofit after adding Flow does not return values

Time:12-31

Recently, I decided to learn a bit about how to write android apps. After read book and checked many codes, blogs etc. I prepared small code which should get a list of data from rest service and present them on a screen in recyclerView. It worked with "hardcoded data", after added retrofit I have seen the data in Log, because I used enqueue with onResponse method. But it is async call, therefore I added Flow with emit and collect methods to handle incoming data. Unfortunately, still it does not work, now even Log is empty.

interface ApiInterface {
    @GET("/api/v1/employees")
    fun getEmployees() : Call<ResponseModel>
}
object ServiceBuilder {
    private val client = OkHttpClient.Builder()
        .addInterceptor(HttpLoggingInterceptor(HttpLoggingInterceptor.Logger.DEFAULT)
            .setLevel(HttpLoggingInterceptor.Level.BODY))
        .build()

    private val retrofit: Retrofit = Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .client(client)
        .build()

    fun<T> buildService(service: Class<T>): T{
        return retrofit.create(service)
    }
}
class EmployeeRepository() {
    fun getEmployees(): Flow<ResponseModel?> = flow {
        val response = ServiceBuilder.buildService(ApiInterface::class.java)
        Log.d("restAPI",response.getEmployees().execute().body()!!.toString() )
        emit( response.getEmployees().execute().body() )
    }
}
class MainViewModel(private val savedStateHandle: SavedStateHandle): ViewModel() {

    init {
        viewModelScope.launch {
            EmployeeRepository().getEmployees().collect {
                Log.d("restAPI", it.toString())
            }
        }
    }
}
class MainActivity : AppCompatActivity() {
    private val mainModel: MainViewModel by viewModels()

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.recyclerView.layoutManager = LinearLayoutManager(this)

        val employee = EmployeeModel(id = 1, employee_age = 11, employee_salary = 12,
                                     employee_name = "ABCD", profile_image = "")
        var employeeList = mutableListOf(employee)
        val adapter = EmployeeListAdapter(employeeList)
        binding.recyclerView.adapter = adapter
    }
}

Maybe I missed something in the code or in logic, I cannot find helpful information in internet. Can anyone tell me what and how should I change my code?

UPDATE:

Thank you ho3einshah! For everyone interested in now and in the future I'd like inform that change from Call to Response:

interface ApiInterface {
    @GET("/api/v1/employees")
    suspend fun getEmployees() : Response<ResponseModel>
}

and change init to getData method:

fun getData() = repository.getEmployees()

were clue to solve the issue. Moreover I called livecycleScope one level above - in AppCompatActivity for passing data directly to adapter:

lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                mainModel.getData().collect { employeeList ->
                    Log.d("restAPI", employeeList.toString() )
                    val adapter = EmployeeListAdapter(employeeList)
                    binding.recyclerView.adapter = adapter
                }
            }
        }

Now I see the list on screen with incoming data.

CodePudding user response:

Hi I hope this answer help you. first because of using GsonConverterFactory add this dependency to your build.gradle(app): implementation 'com.squareup.retrofit2:converter-gson:2.9.0' now change your api service to below code:

import retrofit2.Response
import retrofit2.http.GET

interface ApiInterface {
    @GET("/api/v1/employees")
    suspend fun getList() : Response<ResponseModel>

Please pay attention Response must be from retrofit2.Response

I have used the api you are using it. as a response you have a list with "data" json key. Create a Response model according to Json Response :

data class ResponseModel(
var status : String?,
var data : ArrayList<EmployeeModel>

)

Now this is EmployeeModel :

data class EmployeeModel(
var d:Long,
var employee_age:Long,
var employee_salary:Long,
var employee_name:String,
var profile_image:String

)

class EmployeeRepository {

 fun getEmployees() = flow<Response<EmployeeModel>> {
     val response = RetrofitBuilder.buildService(MainService::class.java).getEmployees()
     Log.e("response",response.body()?.data.toString())
 }

}

and for your viewModel its better to call repository from a method and not in init block :

class MainViewModel : ViewModel() {
private val repository = EmployeeRepository()

fun getData() {
    viewModelScope.launch(Dispatchers.IO) {
      val a =  repository.getEmployees()
          .collect{
          }
    }
}

}

and in your MainActivity initialize MainViewModel like this and call MainViewModel method:

class MainActivity : AppCompatActivity() {
lateinit var mainViewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    mainViewModel = ViewModelProvider(this)[MainViewModel::class.java]
    mainViewModel.getData()
}

}

  • Related