-
Notifications
You must be signed in to change notification settings - Fork 1
/
DX.Threading.Command.pas
133 lines (113 loc) · 3.21 KB
/
DX.Threading.Command.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
unit DX.Threading.Command;
interface
uses
System.SysUtils, System.Classes;
type
TErrorProc = TProc<string>;
TAsyncCommand = class(TThread)
private
FExecutionProc, FDoneProc: TProc;
FErrorProc: TErrorProc;
FOwned: Boolean;
function GetOwned: Boolean;
procedure SetOwned(const Value: Boolean);
protected
procedure Execute; override;
public
constructor Create(const AExecutionProc: TProc; const ADoneProc: TProc = nil; const AErrorProc: TErrorProc = nil;
AFreeOnDone: Boolean = true); reintroduce;
class function Run(const AExecutionProc: TProc; const ADoneProc: TProc = nil; const AErrorProc: TErrorProc = nil;
AFreeOnDone: Boolean = true): TAsyncCommand;
property DoneProc: TProc read FDoneProc;
property ErrorProc: TErrorProc read FErrorProc;
property ExecutionProc: TProc read FExecutionProc;
property Owned: Boolean read GetOwned write SetOwned;
end;
implementation
uses
FMX.Ani, FMX.Types;
{ TAsyncCommand }
constructor TAsyncCommand.Create(const AExecutionProc: TProc; const ADoneProc: TProc = nil; const AErrorProc: TErrorProc = nil;
AFreeOnDone: Boolean = true);
begin
inherited Create(true);
FreeOnTerminate := AFreeOnDone;
FExecutionProc := AExecutionProc;
FDoneProc := ADoneProc;
FErrorProc := AErrorProc;
FOwned := false;
end;
procedure TAsyncCommand.Execute;
var
LMessage: string;
begin
try
if Assigned(ExecutionProc) then
ExecutionProc;
if Assigned(DoneProc) then
Synchronize(
procedure
begin
DoneProc
end);
except
on E: Exception do
begin
if Assigned(ErrorProc) then
begin
LMessage := E.Message;
Synchronize(
procedure
begin
ErrorProc(LMessage);
end);
end;
end;
end;
end;
function TAsyncCommand.GetOwned: Boolean;
begin
TMonitor.Enter(Self);
try
result := FOwned;
finally
TMonitor.Exit(Self);
end;
end;
class function TAsyncCommand.Run(const AExecutionProc, ADoneProc: TProc; const AErrorProc: TErrorProc; AFreeOnDone: Boolean): TAsyncCommand;
begin
result := TAsyncCommand.Create(AExecutionProc, ADoneProc, AErrorProc, AFreeOnDone);
result.Start;
end;
procedure TAsyncCommand.SetOwned(const Value: Boolean);
begin
TMonitor.Enter(Self);
try
FOwned := Value;
finally
TMonitor.Exit(Self);
end;
end;
initialization
// This is a fix for a bad behaviour of FMX' animation timer
// The interval calculation defaults to 10ms which prevents TThread.Synchronize
// to intercept reasonably. See:
(*
constructor TAniThread.Create;
begin
inherited Create(nil);
if not TPlatformServices.Current.SupportsPlatformService(IFMXTimerService, IInterface(FTimerService)) then
raise EUnsupportedPlatformService.Create('IFMXTimerService');
if AniFrameRate < 5 then
AniFrameRate := 5;
if AniFrameRate > 100 then
AniFrameRate := 100;
Interval := trunc(1000 / AniFrameRate / 10) * 10;
*)
// We only care about XE6 and up!
{$IF defined(VER280)} // XE7
TAnimation.AniFrameRate := 30;
{$ELSEIF defined(VER270)} // XE6
AniFrameRate := 30;
{$ENDIF}
end.