Soy nuevo en el desarrollo de Android y estoy tratando de obtener datos json de la API DarkSky, usando OkHttp y GSon. El problema es que necesito devolver de alguna manera la respuesta del método onResponse, pero siempre es nulo.
Aquí está mi código:
class DarkSky : Callback { private var url: String? = null private var forecast: Forecast? = null fun fetchJson(lat: Double, long: Double): Forecast? { this.url = "${Constants.DARK_SKY_BASE_URL}/${Constants.DARK_SKY_KEY}/$lat,$long?exclude=hourly,flags,offset" val request = Request.Builder().url(url!!).build() val client = OkHttpClient() client.newCall(request).enqueue(this) return this.forecast // when I debug this its NULL } override fun onFailure(call: Call, e: IOException) { println("error") } override fun onResponse(call: Call, response: Response) { if (response.isSuccessful) { val body = response.body()?.string() val gson = GsonBuilder().create() val forecast = gson.fromJson(body, Forecast::class.java) parse(forecast) } } private fun parse(response: Forecast) { this.forecast = response //when I debug this, it contains data I need. } }EDITAR:
Lo hizo funcionar con BlockingQueue. Pero no sé. ¿Es una buena idea?
class DarkSky { private var url: String? = null private var forecast: Forecast? = null fun fetchJson(lat: Double, long: Double): ArrayBlockingQueue<Forecast>? { this.url = "${Constants.DARK_SKY_BASE_URL}/${Constants.DARK_SKY_KEY}/$lat,$long?exclude=hourly,flags,offset" val request = Request.Builder().url(url!!).build() val blockingQueue: ArrayBlockingQueue<Forecast> = ArrayBlockingQueue(1) // <<< val client = OkHttpClient() client.newCall(request).enqueue(object : Callback { override fun onFailure(call: Call, e: IOException) { println("error") } override fun onResponse(call: Call, response: Response) { if (response.isSuccessful) { val body = response.body()?.string() val gson = GsonBuilder().create() val forecast = gson.fromJson(body, Forecast::class.java) blockingQueue.add(forecast) // <<< } } }) return blockingQueue } }No quiero aprender malas prácticas.
Eso es porque
client.newCall(request).enqueue(this)se ejecutará de forma asíncrona en el subproceso de fondo. Entonces, cuando regresa, en realidad no tiene un valor asignado.
Solución:
Probablemente necesite pasar un objeto de una clase que se ajuste a cierta interfaz e invoque un método de esa interfaz.
Estos son los cambios que debe hacer
class DarkSky : CallBack { private var url: String? = null private var forecast: Forecast? = null private var onRequestCompleteListener : OnRequestCompleteListener? =null fun fetchJson(lat: Double, long: Double,callback : OnRequestCompleteListener) { this.onRequestCompleteListener = callback this.url = "${Constants.DARK_SKY_BASE_URL}/${Constants.DARK_SKY_KEY}/$lat,$long?exclude=hourly,flags,offset" val request = Request.Builder().url(url!!).build() val client = OkHttpClient() client.newCall(request).enqueue(this) } override fun onFailure(call: Call, e: IOException) { onRequestCompleteListener?.onError() println("error") } override fun onResponse(call: Call, response: Response) { if (response.isSuccessful) { val body = response.body()?.string() val gson = GsonBuilder().create() val forecast = gson.fromJson(body, Forecast::class.java) parse(forecast) } onRequestCompleteListener?.onSuccess(forecast) } private fun parse(response: Forecast) { this.forecast = response //when I debug this, it contains data I need. } } interface OnRequestCompleteListener{ fun onSuccess(forcast :Forecast) fun onError() }