PDA

Ver la Versión Completa : Ejecución bloqueada. Hilos de ejecución


muli
24-09-2015, 17:21:07
Hola a todos. Tengo una aplicación en Android con xe6 que cuando abre una base de datos que tengo en la tarjeta microsd de la tablet, pasa un rato y parece que queda bloqueada, pero no lo está, intenté poner un aniIndicator para que mientras se abre el query y rellena un listview con los datos se mueva el circulito para que el usuario no crea que tiene la aplicación bloqueada. Estuve viendo en san google el asunto de los thread, pero no me aclaro mucho y la información es bastante escasa,alguna ayuda para que cuando le doy a query.open, aparezca el aniIndicator y se mueva hasta que el query finalice de traer los datos.

Saludos. a todos.

Neftali [Germán.Estévez]
25-09-2015, 10:32:50
Échale un vistazo a este link (http://www.fmxexpress.com/easily-use-threads-in-delphi-xe5-firemonkey-on-android-and-ios/.).

muli
11-10-2015, 12:33:01
Este es el código que uso después de visionar diferentes paginas de creación de threads, pero la barra de progreso no avanza, yo lo que quiero es que avance mientras no termina de abrirse la fuente de datos, para que el usuario no crea que la aplicación ha quedado colgada. También pensé en realizar el hilo con la fuente de datos, pero al terminar el hilo pierdo toda la referencia a los datos, por lo que no me sirve. Estoy trabajando con Delphi xe6 y para android. Si en lugar de una barra de progreso se tiene que hacer con una animación, me da igual, el caso es que la aplicación realice algo mientras abre los datos, tampoco son muchos registros, una vez abierta la fuente de datos se mueven perfectamente, incluso si hago un update de un registro es instantáneo.


// Declaro thread
THilo = class(TThread)
Progreso: TProgressBar;
procedure Execute; override;
procedure ActualizarProgreso;
end;

Hilo1: THilo; // variable global o pública
Avance : Integer;

Implementation

procedure THilo.ActualizarProgreso;
begin
Avance:=Avance+1;
Progreso.Value:=Avance;
if Avance>100 then
Begin
Avance:=0;
End;
end;

procedure THilo.Execute;
begin
inherited;
FreeOnTerminate := True;
while not Terminated do
begin
Synchronize(ActualizarProgreso);
end;
end;

// Hasta aquí tengo los procedimientos del thread.
// Luego en el procedimiento de abrir los datos tengo esto.
Procedure TForm1.AbrirDatos.
Begin
ProgressBar1.Value:=0; // Inicio la barra de progreso.
ProgressBar1.Visible:=True;
Avance:=0;

Hilo1 := THilo.Create(True); // Creo hilo de ejecución.
Hilo1.Progreso := ProgressBar1;
Hilo1.Resume;
// Abro datos. Omito campos para hacerlo mas legible.
Query1.Close;
Query1.SQL.Clear;
Query1.Connection:=FdConnection1;
Query1.SQL.Add('Select * From Registros Where Actual=0');
Query1.SQL.Add('Order By Direccion');
if not Query1.Prepared then Query1.Prepare;
Query1.Open;
// Finalizo thread.
Hilo1.Terminate;
FreeAndNil( Hilo1 );

Neftali [Germán.Estévez]
11-10-2015, 17:59:58
Así a primeras, lo que veo es que la variable avance, está definida fuera del thread y la estás utilizando dentro.
defínela dentro, pues no es necesarias fuera, o incluso elimínala, pues no la necesitas.

muli
12-10-2015, 03:27:17
Nada amigo, elimino la variable avance y en su lugar pongo, pero la barra de progreso ni siquiera se mueve, incluso pasa una cosa curiosa en tiempo de diseño le tengo valor 80 para ver el color de la barra y no se lo quite, cuando inicio el procedimiento puedes ver que le paso el valor 0, y ni nada, no hace caso.


Progreso.Value:=Progreso.Value+1;
if Progreso.Value>100 then
Begin
Progreso.Value:=0;
End;

mamcx
12-10-2015, 04:08:30
Estas haciendo todo al revez.

La GUI corre en el thread principal y lo estas poniendo en un background. La parte "lenta" la estas dejando en el thread ppal, bloqueando la GUI.

No hay razon (normalmente) para poner GUI dentro de otro thread, siempre usa otros threads para correr de forma concurrente CPU/IO intensivo.

Por otro lado, si es solo poner un "espera mientras", entonces no tienes que hacer esto. Solo arranca el spinner al inicio, ejecuta la parte "lenta" y paras el spinner al final.

Porque ademas, ese progreso que tienes no sirve de nada...

Y estas masacrando la CPU al tener un while sin un respiro (un sleep o una tarea asincronica).

Y es mala cosa "matar" threads.

Mejor dicho, estudia mas sobre este tema ;)

muli
12-10-2015, 11:45:47
No estoy haciendo ninguna espera, lo que quiero es que mientras el query trae los registros se mueva la barra de progreso, para que no parezca que la aplicación está congelada, o sea, que el usuario vea movimiento mientras se realiza la consulta.

Algún enlace entendible para estudiar más del tema. :):)

AgustinOrtu
12-10-2015, 19:41:36
Revisa este post (http://delphiaccess.com/foros/index.php/topic/11727-mostrar-formulario-que-haga-algo-y-luego-se-cierre/)

mamcx
12-10-2015, 19:43:05
Ya te explique el problema. Lee con cuidado.

Si simplementes copias/pegas un codigo por ahi sin entender como hacer multi-hilos terminaras sin querer incorporando bug(s) y/o haciendo el codigo mas ineficiente.

Un computador moderno (ie: De menos de 4 años para aca) es suficientemente rapido para hacer casi de todo en forma secuencial, y la mayoria de los lenguajes (como delphi) no son optimos para hacer concurrencia, asi que es facil hacer algo con problemas.

AgustinOrtu
12-10-2015, 19:51:18
Estoy casi completamente de acuerdo

Digo casi porque para el caso de mostrar un "espere por favor" mientras se hace cierto procesamiento y no bloquear la UI es algo bastante sencillo en Delphi. Aunque admito que si hay que realizar calculos en paralelo y sincronizacion con Delphi es bastante mas complicado

NicolasP
28-11-2016, 15:16:03
Tema viejo , pero hago un aporte. Después de buscar y leer por varios días post que dicen "lea este post..." lo pude hacer funcionar el AniIndicator para que se "mueva" con un proceso.
Me funciona en windows y también en Android 6.0 con D X7

Form Principal.

procedure TFmMAin.SB_DbReadClick(Sender: Tobject);

begin

PAnelAviso.Visible := true;
AniIndicator1.Enabled := true;
Hilo := THilo.Create(True);
Hilo.Start;
while not Hilo.Finished do
begin
ProgressBar1.value := ProgressBar1.Value +1;
sleep(20);
if ProgressBar1.Value = 100 then
ProgressBar1.Value := 0;
Application.ProcessMessages;
end;
ProgressBar1.Value := 0;
AniIndicator1.Enabled := false;
PAnelAviso.Visible := false;

.....


Nota: El AniIndicator esta en un Panel. Le puse también un Progressbar para ver si funcionaban juntos. y funcionan!. Sin en el Application.ProcessMessages no funcionan.


Unidad para el proceso


unit procesos;

interface
uses
Classes, SysUtils;

type
THilo = class(TThread)
protected
procedure Execute; override;
end;


implementation
uses main;

procedure THilo.Execute;
begin
FmMain.RestRequest1.Execute;
end;

end.



No se si es eficiente, pero no me importa. Lo importante que el usuario crea que lo es (ja) . Y vea que su dispositivo esta "pensando" ... después le podemos echar la culpa a las comunicaciones, etc....
:D