PDA

Ver la versión completa : [Programacion Android] Duda para no dejar bloqueado UI



JJdroid
09/08/2012, 00:36
Buenas, no soy programador de Android (llevo literalmente 2 dias), pero en vez de un hola mundo he querido hacer algo mas grande y mal...

He buscado un poco bastante por foros y nada

Lo que quiero es ir actualizando el contenido de un TextView, dentro de un bucle (pesado no, lo siguiente) que lee un fichero y escribe otro.

Lo que lees por ahi, es ir actualizando con un timer con un manejador, o una asynktask, pero no me vale...

Lo que he hecho, mal pq solo actualiza el contenido del testView al acabar (logico pq lo he puesto mal en el onCreate, q es el hilo del ui y no hay q dejarlo bloqueado)

En el onCreate creado un boton con su listener
calcula.setOnClickListener(new OnClickListener() {

dentro el bucle (que va leyendo fichero y escribiendo otro)
while (){

Actualizacion del testView
}

¿Como se haria bien? (Que bonito habria sido tener un aplication.doevents() o similar :P

Supongo que con un manejador, otro thread pero nu se :(, igual es que con entrada/salida no se puede :S

pakoito
09/08/2012, 02:26
Cuál es la condición de salida de ese while?

juanvvc
09/08/2012, 04:22
¿Por qué no puedes hacerlo con un AsyncTask? Sirven exactamente para eso:

En el onCreate():

(Voy a escribir el código de memoria, tienes que comprobarlo tú)




new ReadAndUpdate().execute(textview);


Y el AsyncTask:



class ReadAndUpdate extends AsyncTask<TextView, Integer, String> {
TextView aquiLoSuelto;

public doInBackground(final TextView... views){
// esto se ejecuta en un hilo distinto del UI, así que no podemos tocar la UI
aquiLoSuelto = views[0];
heLeido=0;
while(heLeido<100) {
heLeido=leeUnRato(); // suponemos que devuelve el porcentaje de fichero leído
publishProgress(heLeido); // publicamos el progreso
}
return "Ya acabé";
}

public onProgressUpdate(int porcentajeLeido) {
// esto se ejecuta en el hilo de UI, cuando llamen a progressUpdate()
aquiLoSuelto.setText("He leido un " + porcentajeLeido + " por ciento");
}

protected void onPostExecute(String msg) {
// esto se ejecuta en el hilo de UI, al final de la ejecución
aquiLoSuelto.setText(msg);
}
}

^MiSaTo^
09/08/2012, 08:16
Cuidadín al pasar el textView al AsyncTask que se pasa como constante y a veces se le va la olla y no se actualiza. De hecho, yo no le pasaría ningún elemento de la UI al AsyncTask, porque como digo no siempre funciona como esperas ;)

JJdroid
09/08/2012, 20:00
Hola juanvvc muchas gracias por responderme.

Pues creo que deje el asynkTask cuando lo probe me daba un pete.

Probando lo tuyo (Aunque pueda que haya metido la zarpa):

Parece que no le mola mucho que se toque el UI desde otro hilo asi:

Al llegar a
aquiLoSuelto.setText("He leido un " + porcentajeLeido + " por ciento");


android.view.ViewRoot$CalledFromWrongThreadExcepti on: Only the original thread that created a view hierarchy can touch its views.

^MiSaTo^
09/08/2012, 20:05
Obviamente, esque no se puede tocar el main thread (osea donde está la UI) desde otro thread. Eso es porque estás manipulando el textview en el doInBackground. De todos modos yo no pasaría el TextView al AsyncTask. La usaría como una inner class del Activity que contenga al textView para poder acceder a él.
Ya digo que lo de pasar elementos de la UI a la asyncTask no es buena idea

JJdroid
09/08/2012, 20:20
Vale, fallo mio, porque no quiero que se lance el bucle nada mas cargar sino cuando pulsaban el boton calcula.

calcula.setOnClickListener(new OnClickListener() {

}

De todas formas lanzada la asynkTask desde el onCreate... es como dice Misato, resultados inesperados...

Gracias Misato y juanvvc... si es que en Android soy muy novato.!

juanvvc
09/08/2012, 21:22
(he cambiado todo el mensaje porque lo había entendido mal :D)

¿Te has dado cuenta de que en el doInBackground() se llama a un método llamado publishProgress()... pero el aquiLoSuelto.setText() se hace en un método llamado onProgressUpdate()

(En el código original y por hacerlo de memoria, había llamado progressUpdate incorrectamente. Es publishProgress, corregido en el código de antes)

Por cierto, lo que dice Misato es totalmente cierto. A mí tampoco me gustaba pasar el TextView, lo hice solo porque me parecía que así quedaba más clara la explicación :brindis:

JJdroid
10/08/2012, 00:34
Gracias, le echare un ojo

Pd: cada vez q se ejecuta el publishProgress() deveria lanzar trigger al onProgressUpdate(), pero en modo debug no veo q pase por ahi...

Bueno a partir de aqui me mirare ejemplosy vere q pasa, lo dicho GRACIAS

juanvvc
10/08/2012, 00:40
Recuerda que el onProgressUpdate() tiene que aceptar los parámetros que le hayas dicho en el genérico. En el ejemplo de arriba, Integer. Es probable que estés declarando una función distinta por tener unos parámetros diferentes y por eso no pase por ella.

Para comprobaar si lo estás declarando correctamente añade un @override justo en la línea de antes de la declaración del método onProgressUpdate() Si falla, es que no estás declarando bien el método.



class ReadAndUpdate extends AsyncTask<TextView, Integer, String> {
(...)

@override
public onProgressUpdate(Integer... porcentajeLeido) { // no recuerdo si esto puede ser un int y ya está
(...)



Para más información, mira la ayuda oficial: http://developer.android.com/reference/android/os/AsyncTask.html

Fíjate que ponen como ejemplo exactamente lo que quieres hacer tú, así que se confirma que la AsyncTask es la solución a tu problema.

JJdroid
10/08/2012, 20:57
Muchas gracias juanvvc por el tiempo que me has dedicado...

Si, es que copie el ejemplo a saco, para la proxima estudiare y me mirare bien los ejemplos ;)

Se le puede pasar un int, pero el tipo debe ser Integer
public onProgressUpdate(Integer... values){
aquiLoSuelto.setText("Va: " + String.valueOf( values[0]));
}

etcs varios

Muy agradecido juanvvc, en serio.