Search code examples
androidkotlinretrofit2kotlin-coroutineskotlin-flow

function inside flow is not getting called during retrofit api call


During api the code inside the 'flow{}' is not getting called, below is the order of my execution. Execution starts from view model

private fun getAppConfig() = viewModelScope.launch {
        _appConfigFlow.update {
            AppConfigState.Loading
        }
        val response = getAppConfigUseCase.invoke()
    }

below is the usecase

class GetAppConfigUseCase @Inject constructor(
    private val repository: AppConfigRepository
) {
    suspend operator fun invoke() = withContext(Dispatchers.IO) {
        repository.getAppConfig()
    }
}

below is the repository

interface AppConfigRepository {
    suspend fun getAppConfig(): Flow<Result<AppConfig>?>
}

below is the repository implementation

@Singleton
class AppConfigRepositoryImp @Inject constructor(
    private val remoteDataSource: AppConfigRemoteDataSource
) : AppConfigRepository {

    override suspend fun getAppConfig(): Flow<Result<AppConfig>?> = flow {
        remoteDataSource.getAppConfigData()
    }
}

below is the remote data source

interface AppConfigRemoteDataSource {
    suspend fun getAppConfigData(): Flow<Result<AppConfig>?>
}

below is the remote data source implementation

class AppConfigRemoteDataSourceImpl @Inject constructor(
    private val apiService: ApiService
) : AppConfigRemoteDataSource {
    override suspend fun getAppConfigData(): Flow<Result<AppConfig>?> = toResultFlow {
        apiService.getAppConfig()
    }

    private fun <T> toResultFlow(call: suspend () -> Response<T>?): Flow<Result<T>?> {
        return flow {
            emit(Result.Loading)
        }
    }
}

I added a debugger in the above functions and I can see that every function is getting called except apiService.getAppConfig(). It is not getting called so I am not getting any result. But if I am using the normal Response<T> from retrofit I am getting the response but not when using the flow. Please help me to find the solution this is api service

@GET(".")
    suspend fun getAppConfig(): Response<AppConfig>

Solution

  • In AppConfigRemoteDataSourceImpl.toResultFlow(), you only return a Flow that emits a Loading state and nothing else. It ignores the lambda parameter you passed to it.

    You probably meant to do:

        private fun <T> toResultFlow(call: suspend () -> Response<T>?): Flow<Result<T>?> {
            return flow {
                emit(Result.Loading)
                emit(call())
            }
        }
    

    I suggest using Flow<Result<T>> instead of Flow<Result<T>?>. There's no case where your Flow would ever emit null, so why make it difficult to use in the collector?