Skip to content

Instantly share code, notes, and snippets.

@Codelaby
Created April 26, 2023 14:08
Show Gist options
  • Save Codelaby/75acbed190f1a67b43b8ce782c680e65 to your computer and use it in GitHub Desktop.
Save Codelaby/75acbed190f1a67b43b8ce782c680e65 to your computer and use it in GitHub Desktop.
Sample Retrofit Flow

Solicitud de un track GPX, con viewModel, retrofit y flow

class APIClient private constructor(context: Context) {
companion object : SingletonHolder<APIClient, Context>(::APIClient) {
//seconds, minutes, hours
private const val MAX_AGE = 60 * 60 * 24
private const val MAX_STALE = 60 * 60 * 24
private const val cacheSize = (10 * 1024 * 1024).toLong() // 10MB cache size
}
private val cacheDirectory = File(context.cacheDir, "http-cache")
private val cache = Cache(cacheDirectory, cacheSize)
private val gson = GsonBuilder()
.setLenient()
.setDateFormat("yyyy-MM-dd HH:mm:ss")
.create()
//OkhttpClient for building http request url
private val okHttpClient = OkHttpClient.Builder()
.cache(cache)
.addInterceptor(CacheInterceptor(MAX_AGE, MAX_STALE))
.build()
private fun retrofit(): Retrofit = Retrofit.Builder()
.baseUrl("api_url")
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.client(okHttpClient)
.build()
val REMOTE_API: APIService = retrofit().create(APIService::class.java)
init {
}
}
interface APIService {
@GET
@Headers("Content-Type: application/xml")
suspend fun getGPXData(@Url url: String): Response<String>
}
class MyViewModel(application: Application) : AndroidViewModel(application) {
private val remoteSource: APIClient
private val _stateItems: MutableStateFlow<TrailState> = MutableStateFlow(TrailState.LOADING)
val trailTrack: StateFlow<TrailState> = _stateItems
init {
remoteSource = APIClient.getInstance(application.baseContext)
}
fun getGPXData(trackUrl: String?) {
if (trackUrl == null) return
viewModelScope.launch {
_stateItems.value = TrailState.LOADING
useCaseGPXData(trackUrl)
.onStart { _stateItems.value = TrailState.LOADING }
.catch { ex ->
_stateItems.value = TrailState.FAILED(ex)
}.collect { result ->
when (result) {
is ResultType.Success -> {
_stateItems.value = TrailState.SUCCESS(result.data!!)
}
is ResultType.Error -> {
_stateItems.value = TrailState.FAILED(result.exception)
}
}
}
}
}
private fun useCaseGPXData(url: String): Flow<ResultType<Gpx>> = flow {
try {
val call = remoteSource.REMOTE_API.getGPXData(url)
if (call.isSuccessful) {
val data = call.body()
val inputStream = ByteArrayInputStream(data?.toByteArray())
val gpxParser = GPXParser()
val gpx = withContext(Dispatchers.IO) { gpxParser.parse(inputStream) }
emit(ResultType.Success(gpx))
} else {
//error en la llamada web, http
emit(ResultType.Error(HttpException(call)))
}
} catch (exp: Exception) {
//captura de cualquier otro error, por ejemplo que no hay internet
emit(ResultType.Error(exp))
}
}.flowOn(Dispatchers.IO)
}
sealed class ResultType<T> {
data class Success<T>(val data: T?) : ResultType<T>()
data class Error<T>(val exception: Exception) : ResultType<T>()
}
/*
Encapsulamiento de los datos, con el modelo de datos
*/
sealed class TrailState {
object LOADING : TrailState()
class SUCCESS(val data: Gpx) : TrailState()
class FAILED(val error: Throwable) : TrailState()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment