Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Desarrollo en Delphi para Android (https://www.clubdelphi.com/foros/forumdisplay.php?f=57)
-   -   Error en Thread (hilo) Android (https://www.clubdelphi.com/foros/showthread.php?t=96665)

jmbarrio 08-04-2024 18:40:02

Error en Thread (hilo) Android
 
Buenas tardes, tengo un trozo de código que recorre los registros de una tabla de memoria y para cada uno de ello hace un insert en una base de datos. Al ejecutarlo en android lo ejecuta bien pero tarda alrededor de 10 segundos y me sala un mensaje en pantalla de que la aplicación no respònde y me pide esperar o aceptar.
Mirando en el foro, vi que lo mejor era hacer un hilo. El código del hilo lo creo en un bottonclick.

Código Delphi [-]
Thread := TThread.CreateAnonymousThread(
    procedure
      begin
         while not FDMemTable1.Eof do
    begin
      try
        with F_data.FDQryInsertCliente do
          begin
            Active := False;
            Sql.Clear;
            sqlstr:= 'Insert into clientes (CLI_COD, CLI_NOMCOM, CLI_DIRCOM, CLI_DIRPOB, CLI_ZONA) values(' + '''' + FDMemTable1.FieldByName('cli_cod').AsString + '''' +
                     ',' + '''' + StringReplace(FDMemTable1.FieldByName('cli_rsocial').AsString, '''', '', [rfReplaceAll, rfIgnoreCase]) + '''' + ',' +
                     '''' + StringReplace(FDMemTable1.FieldByName('cli_direc').AsString, '''', '', [rfReplaceAll, rfIgnoreCase]) + '''' +
                     ',' + '''' + StringReplace(FDMemTable1.FieldByName('cli_pobla').AsString, '''', '', [rfReplaceAll, rfIgnoreCase]) + '''' + ',' + '''' +
                     FDMemTable1.FieldByName('cli_zona').AsString + '''' + ')';
            Sql.add(sqlstr);
            ExecSQL;
          end;
        contador := contador + 1;
        FDMemTable1.Next;
        //label1.Text := contador.ToString + ' de ' + nClientes.ToString;
        //sleep(1);
        TThread.Synchronize(TThread.CurrentThread,
        procedure
        begin
        Progressbar1.Value := Progressbar1.Value +1
        end);
        //Application.ProcessMessages;


      except
        on e:exception do
          showmessage(e.Message + ' ' + sqlstr)
      end;
    end;

      end);

  Thread.FreeOnTerminate := True;
  Thread.Start;
  showmessage('Sincronizacion de Clientes Completada. ' + contador.ToString + 'Clientes Traspasados');

el programa no recorre los registros de la tabla de memoria, me sale el mensaje Sincronizacion de clientes completada. 0 clientes traspasados.
Y seguidamente se va llenando la barra de progreso.

Podéis echarme una mano a ver que estoy habiendo mal.?

Muchas gracias, un saludo.

jhonalone 09-04-2024 01:08:04

Hola jmbarrio.
Tuve un problama parecido, echa un vistazo a este hilo.

Los consejos de dani36652, me ayudaron a resolver el problema.

Un saludo.

jmbarrio 09-04-2024 08:54:09

Hola Johnalone, lo que estuve viendo fue esa ayuda que comentas. Pero es que no se que hago mal en el código ya que no recorre los registros de la tabla de memoria.

Gracias, un saludo.

fjcg02 09-04-2024 09:11:08

Hola,

prueba a poner FDMemTable1.First al principio del todo.

Todo supone que se cumple la condición FDMemTable1.Eof y no recorre el bucle.

Saludos

Neftali [Germán.Estévez] 09-04-2024 09:21:41

Cita:

Empezado por jmbarrio (Mensaje 555261)
...tengo un trozo de código que recorre los registros de una tabla de memoria y para cada uno de ello hace un insert en una base de datos. Al ejecutarlo en android lo ejecuta bien pero tarda alrededor de 10 segundos y me sala un mensaje en pantalla de que la aplicación no respònde y me pide esperar o aceptar.

Mirando en el foro, vi que lo mejor era hacer un hilo. El código del hilo lo creo en un bottonclick.
Podéis echarme una mano a ver que estoy habiendo mal.?

Como solución genérica, pasar las cosas a un Thread cuando el programa se ralentiza puede ser una buena opción, pero no siempre es la más adecuada, ya que los threads tienen sus particuladidades.
Tampoco vale, coger el código "antiguo", pasarlo a un thread y esperar que funcione (tal vez sí, pero no suele ser lo habitual).

Lo primero decir, que las operaciones con Bases de Datos en threads, en según qué casos requieren conexiones diferenes. Por ejemplo, en ADO no puedes usar la misma conexión en 2 threads, porque el componente de conexión no es "thread-safe";En el caso de Firedac hay que mirar bien las especificaciones, porque también tiene sus partocularidades (https://docwiki.embarcadero.com/RADS...ading_(FireDAC)).

En segundo lugar, veo que estás accediendo a componentes directamente desde el thread que están definidos "fuera" (F_data, FDMemTable1, contador); Almenos yo no los veo ahí. Ese acceso te va a dar problemas, puesto que lo estás haciendo sin sincronizar.

Este código no tiene sentido:
Código Delphi [-]
Thread.Start;
showmessage('Sincronizacion de Clientes Completada. ' + contador.ToString + 'Clientes Traspasados');

El ShowMessage va a salir nada más iniciar el proceso, no al final.

jmbarrio 09-04-2024 10:29:58

Cita:

Empezado por fjcg02 (Mensaje 555268)
Hola,

prueba a poner FDMemTable1.First al principio del todo.

Todo supone que se cumple la condición FDMemTable1.Eof y no recorre el bucle.

Saludos

El first lo tengo antes de la declaración del hilo, te refieres a meterlo dentro del procedure del Hilo?

Gracias, un saludo.

jmbarrio 09-04-2024 11:26:54

Cita:

Empezado por Neftali [Germán.Estévez] (Mensaje 555269)
Como solución genérica, pasar las cosas a un Thread cuando el programa se ralentiza puede ser una buena opción, pero no siempre es la más adecuada, ya que los threads tienen sus particuladidades.
Tampoco vale, coger el código "antiguo", pasarlo a un thread y esperar que funcione (tal vez sí, pero no suele ser lo habitual).

Lo primero decir, que las operaciones con Bases de Datos en threads, en según qué casos requieren conexiones diferenes. Por ejemplo, en ADO no puedes usar la misma conexión en 2 threads, porque el componente de conexión no es "thread-safe";En el caso de Firedac hay que mirar bien las especificaciones, porque también tiene sus partocularidades (https://docwiki.embarcadero.com/RADS...ading_(FireDAC)).

En segundo lugar, veo que estás accediendo a componentes directamente desde el thread que están definidos "fuera" (F_data, FDMemTable1, contador); Almenos yo no los veo ahí. Ese acceso te va a dar problemas, puesto que lo estás haciendo sin sincronizar.

Este código no tiene sentido:
Código Delphi [-]
Thread.Start;
showmessage('Sincronizacion de Clientes Completada. ' + contador.ToString + 'Clientes Traspasados');

El ShowMessage va a salir nada más iniciar el proceso, no al final.

Hola Neftalí, tienes toda la razón, pensaba que el showmessage saldría al finalizar el hilo. ¿Cómo puedo enterarme de la finalización del hilo para yo poder sacar ese mensaje?
Gracias. un saludo

Neftali [Germán.Estévez] 09-04-2024 13:21:41

Cita:

Empezado por jmbarrio (Mensaje 555277)
...pensaba que el showmessage saldría al finalizar el hilo. ¿Cómo puedo enterarme de la finalización del hilo para yo poder sacar ese mensaje?


Prueba con el evento OnTerminate del TThread.
Aunque sigo pensando que este es el menor de tus problemas. Creo que si no cambias código ese thread te va a dar problemas.

jmbarrio 09-04-2024 13:33:46

Cita:

Empezado por Neftali [Germán.Estévez] (Mensaje 555288)
Prueba con el evento OnTerminate del TThread.
Aunque sigo pensando que este es el menor de tus problemas. Creo que si no cambias código ese thread te va a dar problemas.

Ya he conseguido que funcione como yo quería, muchas gracias por toda la ayuda. Es mi primera apk para android y estáis siendo de gran ayuda.

Hasta la próxima.

Un saludo a tod@s


La franja horaria es GMT +2. Ahora son las 22:06:32.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi