Обработка сообщений Firemonkey с использованием TMessageManager и TThread.Queue

Как и многим другим разработчикам Firemonkey, мне нужно общее мультиплатформенное решение для отправки сообщений из потока в основной поток (для замены PostMessage). Мне нужно, чтобы он также работал на iOS.

Существует решение François Piette, которое реализовано для Android и Windows, но не для iOS: TMessagingSystem.

Однако я думаю, что это можно сделать намного проще, используя "новый" TMessageManager в сочетании с TThread.Queue(). Но никто не опубликовал код с использованием этого подхода, который действительно работает (например, это неполный).

У вас есть проверенная реализация, которой вы хотели бы поделиться с сообществом (или, может быть, просто предложения, как правильно ее реализовать)?


person Hans    schedule 03.10.2014    source источник
comment
Используйте TThread.Queue и замыкания. Оба работают на любой платформе. uweraabe.de/Blog/2011/01 /30/   -  person Sir Rufo    schedule 03.10.2014
comment
Обратите внимание, что TThread.Synchronize() и TThread.Queue() были нарушены в каждой версии FireMonkey до XE7. См. QC #123579 для получения подробной информации и обходного пути.   -  person Remy Lebeau    schedule 03.10.2014


Ответы (1)


Хорошо, вот моя реализация. Я не использовал TMessagingSystem, так как он, кажется, просто добавляет сложности (по крайней мере, для моей ситуации). Пока это работает, но если у кого-то есть предложения по улучшению, я буду рад улучшить его.

Я просмотрел решение Уве Раабе но я хотел сделать его более простым и легким для реализации в большой кодовой базе, которую я конвертирую в FMX. С приведенным ниже решением я могу просто заменить все PostMessage() на gMessageHandler.PostMessage (удалив аргумент дескриптора выигрыша) и добавить функции сообщений в форму в tMainForm.MessageCallBack.

Я создал небольшой модуль, который я могу включать везде, где мне нужна функция PostMessage. Этим местам не нужно знать о форме:

unit MessageHandler
interface
tAllOSMessage = procedure(aMessageID, aData1, aData2: integer) of object;
tAllOSMessageHandler = class
private
  fOnMessage : tAllOSMessage;
public
  constructor Create(aMessageCallBack: tAllOSMessage);
  procedure PostMessage(aMessageID, aData1, aData2: integer; aSourceThread: TThread = nil);
end;

var
  gMessageHandler: tAllOSMessageHandler;

implementation

constructor tAllOSMessageHandler.Create(aMessageCallBack: tAllOSMessage);
begin
  fOnMessage := aMessageCallBack;
end;

procedure tAllOSMessageHandler.PostMessage(aMessageID, aData1, aData2: integer; aSourceThread: TThread);
begin
  if aSourceThread=nil then
    aSourceThread := TThread.CurrentThread;
  aSourceThread.Queue(nil, procedure
                           begin
                             if Assigned(fOnMessage) then
                               fOnMessage(aMessageID, aData1, aData2);
                           end  );
end;
end.

Затем я добавляю эти строки в основной блок формы:

//Added to main form:
tMainForm = class(TForm)
...
procedure MessageCallBack(aMessageID, aData1, aData2: integer);

//Added to MainFormCreate
gMessageHandler := tAllOSMessageHandler.Create(MessageCallBack);

//Added to MainFormDestroy
FreeAndNil(gMessageHandler)

procedure tMainForm.MessageCallBack(aMessageID, aData1, aData2: integer);
begin
  case aMessageID of
    MyMessage1 :  MyFunction1(aData1,aData2);
    ...
  end;
end;
person Hans    schedule 30.10.2014
comment
Почему вы возитесь с aSourceThread? Просто используйте TThread.Queue(nil,...) это в основном то же самое. - person ciuly; 05.11.2014
comment
@ciuly: Отлично, тогда исходный код может стать еще проще :-) Я не помню, почему появился aSourceThread. - person Hans; 05.11.2014