in the OnDestroy-Event of my Form I check if the mqttclient is connected and if so, I disconnect and destroy it:
procedure TForm1.FormDestroy(Sender: TObject);
begin
if FMqttClient.IsConnected then begin
FMqttClient.Disconnect();
end;
FreeAndNil(FMqttClient);
end;
However, the broker sends the last will testament even though the connection should be closed gracefully.
I assume, that the disconnecting process is not yet finished when I call the FreeAndNil(FMqttClient) and therefore the disconnect packet does not arrive at the broker. Without FreeAndNil(FMqttClient) the LWT is not send.
How can I wait with the FreeAndNil until the connection is closed gracefully?
The disconnection is asynchronous and the application should wait until the TMSMQTTClient.OnConnectedStatusChanged event has AConnected set to false before destroying the TMSMQTTClient component.
All this is implemented in these demos :
\Demo\HighPerformance
\Demo\LazarusSimple
They use the TForm.OnCloseQuery and TMSMQTTClient.OnConnectedStatusChanged events to close the connection gracefully following these steps :
TMainForm.FormCloseQuery set CanClose to false, sets FClosing to true and calls TMSMQTTClient.Disconnect.
TMSMQTTClient.OnConnectedStatusChanged is triggered with AConnected set to false and calls close.
Thank you, the HighPerformance example works!
I tried the lazarus example first (in Delphi), but here the Application got stuck at closing (mqtt was disconnected but the application hangs and is not responsive)
Sorry, I was not clear about that. I copied the relavant code snippets from the Lazarus example into my project and tried it.
The TThread.ForceQueue from the HighPerformance example did the trick. TThread.ForceQueue works also in Lazarus, so I wonder why this is not also present in the Lazarus example?
The Lazarus demo always sets TMSMQTTClient.SyncedEvents to True but the FMX demo has a switch to set a custom TMSMQTTClient.SyncedEvents value.
The TMSMQTTClient.OnConnectedStatusChanged event might run in the context of a background thread or the main application thread in the FMX demo.
The form must always be destroyed in the main application thread and that's why it has a TThread.ForceQueue call.
Besides that, LCL, VCL and FMX have a completely different implementation underneath. Even different Delphi versions have significant implementation changes that may require slightly different application code.
The Lazarus demo works correctly without a TThread.ForceQueue call but using the same code in Delphi may require a few changes