PDA

Ver la Versión Completa : [ CONSULTA ] Problema con Threads


Dild0
11/04/13, 21:26:41
Muy buenas un día mas,

Ando un poco pez con el java ya que yo soy de base de datos y estoy acostumbrado al plsql codigo lineal y no se ejecuta un paso sin terminar el otro, mi problema los hilos....


Estoy haciendo pruebas con la api de google images, en resumen tengo una clase que implenta una llamada con resultado un json donde me esta devolviendo todas las url de imagenes a buscar, por lo que he leido y para conseguir que funcione debía meterlo en un nuevo thread y así lo he hecho,

Ahora quiero jugar con esas url y para hacer una prueba quiero imprimirla en un textView pero con el tema de los hilos no pinta naaaaada y si esta devolviendome urls.... :cry::cry:

Algún experto?


public class probar extends SherlockActivity {

private TextView texto1;
private ApiGImages googleimg = new ApiGImages(null);

@Override
protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);
setContentView(R.layout.probar);
texto1 = (TextView) findViewById(R.id.textView1);

Thread thread = new Thread(new Runnable() {
public void run() {
googleimg.BuscarImagenes("panchito");
try {

texto1.setText(googleimg.getJArray().getJSONObject (0)
.getString("unescapedUrl"));



} catch (Exception e) {

}

}
});
thread.start();

}
}



PD: siento hacer preguntas tan tontas que seguro no tienen nada de dificultad pero me tiene parado to la tarde... yo si quereis una query os la monto jejej

kriogeN
11/04/13, 22:07:13
Los cambios en las views deben hacerse en el hilo principal.

Prueba poniendo a continuación del setText lo siguiente:

texto1.post(new Runnable() {
public void run() {
texto1.invalidate();
}
});

Dild0
11/04/13, 22:32:27
Funciona perfectamente!!!!


Pero puedes explicarme que hace porq ahora si???


Voy a tener q buscar información sobre los hilos.... entiendo entoces que todos los eventos on deben hacerse siempre en el hilo principal pero me has dejado un poco perdido con el invalidate ejejje

gracias una vez más

kriogeN
11/04/13, 23:06:55
El invalidate le dice a la Activity que debe volver a pintar el control que estás invalidando, y al volver a pintarse ya te la pinta con el texto nuevo.

En tu caso necesitas hacerlo porque el setText lo has hecho fuera del hilo principal, y por tanto aunque has cambiado el texto no le ha dicho al hilo principal que debe volver a pintarlo.

Y ahí es donde entra el "post", lo que hace es decirle al control que cuando vuelva a estar disponible en el hilo principal ejecute el contenido del "Runnable" en dicho hilo.

mocelet
11/04/13, 23:08:22
EDIT: No había visto el mensaje de antes xD

El invalidate es para que Android repinte el componente en cuestión. Con los TextView lo hace cuando quiere... vamos, que el setText cambia el texto internamente pero como ya estaba pintado a veces no lo refresca.

En vez del post new Runnable que comenta kriogeN es más rápido (cómodo) llamar simplemente a texto1.postInvalidate(), que es lo mismo y está pensado para estos casos.

kriogeN
11/04/13, 23:14:34
EDIT: No había visto el mensaje de antes xD

El invalidate es para que Android repinte el componente en cuestión. Con los TextView lo hace cuando quiere... vamos, que el setText cambia el texto internamente pero como ya estaba pintado a veces no lo refresca.

En vez del post new Runnable que comenta kriogeN es más rápido (cómodo) llamar simplemente a texto1.postInvalidate(), que es lo mismo y está pensado para estos casos.

Cierto, no había caído en el postInvalidate, internamente hacen lo mismo que he puesto yo, pero efectivamente son mucho más cómodos.

Lo que ocurre es que normalmente no tengo que usarlos, solamente con algunas ImageView un poco puñeteras después de bajar imágenes desde Internet, pero yo lo hago todo con AsyncTask y en el 99% de los casos los "set" a Views que hago en el "onPostExecute" funcionan bien.

Dild0
11/04/13, 23:33:19
de lujo,,,, pues siguiente prueba usar las url que me devuelve descargar las imagenes y meterlas a los imageview



gracias !!!!

mocelet
11/04/13, 23:46:48
Los invalidate en mis apps se han convertido en parte del ritual de magia negra (acompañan al Project - Clean cuando el R se vuelve loco o a las configuraciones extrañas del proguard para funcionar con admob).

A mí realmente creo que no me ha pasado nunca, empecé a meterlos porque a muchos usuarios les pasaban cosas raras de textos que no cambiaban, puntuaciones que seguían igual, etc. Eso lo solucionó (y el setText lo hacía incluso desde el hilo principal).

La teoría dice que si cambias algo debería auto invalidarse... así que es un suceso paranormal :)

Dild0
14/04/13, 23:15:47
Buenas,,, sigo teniendo problemas con el pintado.... hace lo q quiere

Me descarga la imagen, pero no la redibuja sin embargo es apagar la pantalla encender y ahi está


imagen = (ImageView) findViewById(R.id.IMG);



Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
DescargaImagen
.download(
"http://www.trompospeonza.eoldal.hu/img/original/3/peonza-5.gif",
imagen);
imagen.postInvalidate();




} catch (Exception e) {
e.printStackTrace();
}
}
});

thread.start();

mocelet
14/04/13, 23:43:00
¿El DescargaImagen.download bloquea el hilo hasta que recibe la imagen o no? Por si acaso el postInvalidate se ejecuta antes de que se haya descargado (en cuyo caso no valdría para nada).

Dild0
15/04/13, 08:43:54
¿El DescargaImagen.download bloquea el hilo hasta que recibe la imagen o no? Por si acaso el postInvalidate se ejecuta antes de que se haya descargado (en cuyo caso no valdría para nada).

tiene toda la pinta de ir por ahí los tiros,,,
Ademas me estoy creando un hilo cuando creo q no haría falta ya que tengo esto un AsyncTask


Tengo una clase que contiene un Asyntask que me descarga la imagen y me guarda el bitmap (resultado) en una variable privada, ademas tengo este metodo que llama al asyntask.



public void download(String URL, ImageView imageView) {

GetXMLTask task = new GetXMLTask();
task.execute(URL);
//en el post execute del task me devuelve un Bitmap resultado a la clase
//Entiendo que hay que parar aqui hasta que el Asyntask acabe...

imageView.setImageBitmap(resultado);
}

}



¿como lo bloqueo?

gracias de nuevo

mocelet
15/04/13, 10:04:27
No tienes que bloquear nada, simplemente llama al postInvalidate después de poner la imagen nueva en el código de descarga (después del setImageBitmap)

Dild0
15/04/13, 10:47:34
No tienes que bloquear nada, simplemente llama al postInvalidate después de poner la imagen nueva en el código de descarga (después del setImageBitmap)

Perdona pero no lo entiendo así, ya que hasta q el asyntask no acaba mi variable estaría a nula, consecuencia me la pinta vacía..

Te pongo todo el codigo.





ImageView a;
private DescargarImagenes PPP = new DescargarImagenes();

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);
setContentView(R.layout.probar);
a = (ImageView) findViewById(R.id.IMG);
PPP.DownloadImage("http://www.trompospeonza.eoldal.hu/img/original/3/peonza-5.gif",a);
}
}





public class DescargarImagenes {

private Bitmap resultado;

public DescargarImagenes() {
super();
}

public void DownloadImage(String URL, ImageView imageView) {

GetXMLTask task = new GetXMLTask();
task.execute(URL);
imageView.setImageBitmap(resultado);
imageView.postInvalidate();

}

private class GetXMLTask extends AsyncTask<String, Void, Bitmap> {
@Override
protected Bitmap doInBackground(String... urls) {
Bitmap map = null;
for (String url : urls) {
map = downloadImage(url);
}
return map;
}

// Sets the Bitmap returned by doInBackground
@Override
protected void onPostExecute(Bitmap result) {

resultado = result;

}

// Creates Bitmap from InputStream and returns it
private Bitmap downloadImage(String url) {
Bitmap bitmap = null;
InputStream stream = null;
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inSampleSize = 1;

try {
stream = getHttpConnection(url);
bitmap = BitmapFactory.decodeStream(stream, null, bmOptions);
stream.close();
} catch (IOException e1) {
e1.printStackTrace();
}
return bitmap;
}

// Makes HttpURLConnection and returns InputStream
private InputStream getHttpConnection(String urlString)
throws IOException {
InputStream stream = null;
URL url = new URL(urlString);
URLConnection connection = url.openConnection();

try {
HttpURLConnection httpConnection = (HttpURLConnection) connection;
httpConnection.setRequestMethod("GET");
httpConnection.connect();

if (httpConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
stream = httpConnection.getInputStream();
}
} catch (Exception ex) {
ex.printStackTrace();
}
return stream;
}
}

}

kriogeN
15/04/13, 10:53:03
Estás poniendo una imagen nula en el ImageView porque lo haces justo después de lanzar el Execute del GetXMLTask.

Lo que tienes que hacer en enviar el ImageView al GetXMLTask (en el constructor del GetXMLTask lo puedes hacer).

Y en el onPostExecute hacer esto:

imageView.setImageBitmap(result);
imageView.postInvalidate();

Dild0
15/04/13, 11:45:34
Estás poniendo una imagen nula en el ImageView porque lo haces justo después de lanzar el Execute del GetXMLTask.

Lo que tienes que hacer en enviar el ImageView al GetXMLTask (en el constructor del GetXMLTask lo puedes hacer).

Y en el onPostExecute hacer esto:

imageView.setImageBitmap(result);
imageView.postInvalidate();

:platano::platano::platano::platano: :besito:

http://youtu.be/wxtNj6IhSnk

Dild0
17/04/13, 22:25:32
Hola, me surge una duda viendo el comportamiento que estoy teniendo....

En el layout tengo el gridview que carga imagenes y un boton que abre una nueva activity,

Al pulsar el botón para abrirse la nueva activiad no carga o es muy lento ya que tengo hilos por otro lado ejecutandose tanto asyntask dentro de clases y trheads, como puedo cancelar todos esos hilos que haya por detras????

sl2

Dild0
19/04/13, 12:40:03
Hola, me surge una duda viendo el comportamiento que estoy teniendo....

En el layout tengo el gridview que carga imagenes y un boton que abre una nueva activity,

Al pulsar el botón para abrirse la nueva activiad no carga o es muy lento ya que tengo hilos por otro lado ejecutandose tanto asyntask dentro de clases y trheads, como puedo cancelar todos esos hilos que haya por detras????

sl2

Me cito, por si le sirve alguna vez a alguien.

Parece ser que los asyntask se ejecutan en un único hilo hasta la version 3.0 que permiten elegir cargarlos en un pool de hilos (con este comando THREAD_POOL_EXECUTOR), quiere decir que hasta q un asyntask no finaliza no se llama al doInBackground del siguiente (si al onPreExecute).

Mi segundo activity llamaba a un asyntask que se quedaba en cola de ahi la tardanza. Para solucionarlo guarde todos mis task en una coleccion y en el onStop los fui cancelando quedando el task de mi nueva activity el primero de la cola y ya ir todo como la seda.


http://developer.android.com/intl/es/reference/android/os/AsyncTask.html


Si he dicho algo incorrecto que me corrijan los expertos.

Sl2 y gracias....

mocelet
19/04/13, 13:01:12
¡Gracias por la info! Me parece un cambio muy radical por parte del API de Android, pero efectivamente es tal como indicas y puede dar muchos quebraderos de cabeza no saberlo.