PDA

Ver la Versión Completa : Clases internas anónimas y variables externas


oxot
25/03/15, 11:06:35
Buenos días,
estoy programando un app que hace una serie de consultas REST para lo que he decido usar la librería loopj (loopj.com/android-async-http/) para que se encargue de manejar todas las tareas asíncronas.

Entonces, tengo una activity contenera, un fragment que tiene una lista y otra clase que me guarda todas las consultas REST.

Mi problema es el siguiente:
Cuando realizas cualquier consulta, por ejemplo un get, lo haces por ejemplo con:


AsyncHttpClient client = new AsyncHttpClient();
client.get("http://www.google.com", new AsyncHttpResponseHandler() {
override
public void onSuccess(int statusCode, Header[] headers, byte[] response) {
// called when response HTTP status is "200 OK"
}

override
public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) {
// called when response HTTP status is "4XX" (eg. 401, 403, 404)
}
});


y como véis se utilizan clases internas anónimas como manejadores. El problema es que en onSuccess yo quiero actualizar una lista externa (que tengo en la clase fragment) pero Java protesta porque desde clases internas anónimas sólo puede manejar variables de método 'final' o variables de clase (que serían de la clase dónde están las consultas REST).

El problema es que no puedes hacer un método en plan

public Lista miMetodo(){
hazLaConsultaGet();
return laLista;
}


porque la consulta es asíncrona y entiendo que el método no espera a que retorne la consulta sino que devolverá una lista inválida.

Tampoco puedo hacer un return en onSuccess porque tengo que sobreescribir el método de clase y es de tipo void (menudo tela porque en asynctask esto te soluciona el problema).

Yo sólo veo dos soluciones pero me gustaría que gente que sabe de Java más que yo me contase si hay algún procedimiento estándar para estas situaciones:
1.- Usar listeners que implemento en la clase en la que tengo la lista.
2.- Hacer el handler no anónimo instanciándolo antes de la consulta (aunque no estoy seguro que esto resolviese el problema)

A ver si alguien se anima a darme ideas.

:gracias:

PS. Espero haber explicado claramente cómo va el tema. Es un poco lioso pero lo he tratado de simplificarlo.

mocelet
25/03/15, 12:01:31
Lo único que necesitas es una referencia al objeto que quieras llamar, pero de tipo final, claro.

Es decir, antes del client.get(...) pones un:

final ClaseQueSea objeto = instanciaQueQuierasUsar

Y dentro de onSuccess o onFailure puedes llamar a cualquier método de ese objeto que no te dará la brasa con lo de que no es final.

Como bien dices, la gracia del asíncrono es que no bloquea el hilo de ejecución, simplemente se ejecuta algo en segundo plano y cuando termina avisa. Los callbacks o listeners de esa biblioteca los hace en el hilo principal, así que una preocupación menos.

oxot
25/03/15, 12:47:29
Lo único que necesitas es una referencia al objeto que quieras llamar, pero de tipo final, claro.

Es decir, antes del client.get(...) pones un:

final ObjetoQueSea objeto = instanciaQueQuierasUsar

Y dentro de onSuccess o onFailure puedes llamar a cualquier método de ese objeto que no te dará la brasa con lo de que no es final.

Como bien dices, la gracia del asíncrono es que no bloquea el hilo de ejecución, simplemente se ejecuta algo en segundo plano y cuando termina avisa. Los callbacks o listeners de esa biblioteca los hace en el hilo principal, así que una preocupación menos.

Entiendo, al pasar la referencia del objeto lo que es final será la referencia pero no el objeto en sí, del que podré modificar su contenido.
Esto es lo que me propones verdad?

Me costaría adaptarlo a mi app porque estoy trabajando con arrays de objetos (cada objeto un elemento de la lista, supongo que tendría que borrar su contenido y volver a rellenarla) pero sin embargo me la apunto porque es algo en lo que no había pensado.

Le estoy dando una oportunidad a los listeners, con los que hasta ahora no había trabajado :-)

kriogeN
25/03/15, 13:04:41
Entiendo, al pasar la referencia del objeto lo que es final será la referencia pero no el objeto en sí, del que podré modificar su contenido.
Esto es lo que me propones verdad?

Me costaría adaptarlo a mi app porque estoy trabajando con arrays de objetos (cada objeto un elemento de la lista, supongo que tendría que borrar su contenido y volver a rellenarla) pero sin embargo me la apunto porque es algo en lo que no había pensado.

Le estoy dando una oportunidad a los listeners, con los que hasta ahora no había trabajado :-)

Es la misma referencia que el objeto que no es final, pero de esa forma "engañas" (realmente no es engañarlo, pero para que me entiendas) a Java para que lo acepte. Yo también uso ese truco para eventos en Adapters basados en la posición.

Lo único que hace un final es que no puedes cambiar la referencia, pero el objeto será el mismo.

Es decir, si tienes un objeto de tipo ArrayList es lo mismo hacer:

ArrayList a = new ArrayList();
a.add(e);

Que hacer:

ArrayList a = new ArrayList();
final ArrayList b = a;
b.add(e);

En ambos casos al final "a" contendrá al elemento "e"

Lo que no puedes hacer es esto:

final ArrayList b = new ArrayList();
b = new ArrayList();

En ese caso Java se quejará porque b es final, y por tanto no puedes cambiar su referencia.