Hi I have a multidevice APP based on FMX.
The synch database process takes longer time, I need a AniIndicator1 enabled to tell user to wait.
Following code tested in n android phone, sometime works, sometime only finish the first synch DB function, sometimes finish first 3 and then exited. Sometimes none of the sychDB function was taken place.
procedure TForm1.BtnSyncDBClick(Sender: TObject);
begin
Application.ProcessMessages;
memo3.Lines.Add('Start synchronising...');
AniIndicator1.Visible:=true;
AniIndicator1.Enabled:=true;
TThread.CreateAnonymousThread(
procedure
begin
try
SynchDB_A;
memo3.Lines.Add('finish 0');
SynchDB_B;
memo3.Lines.Add('finish 1');
SynchDB_C ;
memo3.Lines.Add('finish 2');
SynchDB_D;
memo3.Lines.Add('finish 3');
finally
AniIndicator1.Enabled := False;
AniIndicator1.Visible := False;
end;
end
).start;
end;
So, I am wondering if I can put the AniIndicator1.enable function in a child thread and use the main thread to synchDB?
Tried following code , not working as expected.
procedure TForm1.BtnSyncDBClick(Sender: TObject);
begin
TThread.CreateAnonymousThread(
procedure
begin
try
TThread.Synchronize (TThread.CurrentThread,
procedure ()
begin
Memo1.lines.Add('Start... ');
AniIndicator1.Visible := True;
AniIndicator1.Enabled := True;
end);
finally
end;
end
).Start;
try
SynchDB_A;
memo3.Lines.Add('finish 0');
SynchDB_B;
memo3.Lines.Add('finish 1');
SynchDB_C ;
memo3.Lines.Add('finish 2');
SynchDB_D;
memo3.Lines.Add('finish 3');
finally
AniIndicator1.Enabled := False;
AniIndicator1.Visible := False;
end;
end;
Any expert could help with this , either fix the first code to guarantee always work, child thread not being killed, or start SynchDB in the main process and enable AniIndicator1 in a child thread and make it spinning. Or any other easy way to tell user to wait while the synchDB working?
thanks in advance.
You can't directly access UI controls from within a worker thread, like you are doing. You MUST synchronize that access to the main UI thread.
procedure TForm1.BtnSyncDBClick(Sender: TObject);
var
Thread: TThread;
begin
Application.ProcessMessages;
memo3.Lines.Add('Start synchronising...');
AniIndicator1.Visible := True;
AniIndicator1.Enabled := True;
Thread := TThread.CreateAnonymousThread(
procedure
begin
SynchDB_A; // <-- must do thread-safe work!
TThread.Queue(nil,
procedure
begin
memo3.Lines.Add('finish 0');
end
);
SynchDB_B; // <-- must do thread-safe work!
TThread.Queue(nil,
procedure
begin
memo3.Lines.Add('finish 1');
end
);
SynchDB_C; // <-- must do thread-safe work!
TThread.Queue(nil,
procedure
begin
memo3.Lines.Add('finish 2');
end
);
SynchDB_D; // <-- must do thread-safe work!
TThread.Queue(nil,
procedure
begin
memo3.Lines.Add('finish 3');
end
);
end
);
Thread.OnTerminate := SyncDone;
Thread.Start;
end;
procedure TForm1.SyncDone(Sender: TObject);
begin
AniIndicator1.Enabled := False;
AniIndicator1.Visible := False;
if TThread(Sender).FatalException <> nil then
memo3.Lines.Add('Error: ' + Exception(TThread(Sender).FatalException).Message);
end;
The reason your second code doesn't work is because the main UI thread is blocking doing all of the work, so it can't update the UI until that work is finished. Hence the need for doing non-UI work in a thread.