├── Example
├── AndroidManifest.template.xml
├── Bin
│ ├── FastMM_FullDebugMode.dll
│ └── FastMM_FullDebugMode64.dll
├── Entitlement.TemplateOSX32.xml
├── Entitlement.TemplateiOS.xml
├── FMain.fmx
├── FMain.pas
├── ProjectTimerQueues.groupproj
├── TimerQueues.deployproj
├── TimerQueues.dpr
├── TimerQueues.dproj
├── TimerQueues.res
├── TimerQueuesConsole.deployproj
├── TimerQueuesConsole.dpr
├── TimerQueuesConsole.dproj
├── TimerQueuesConsole.res
├── info.plist.TemplateOSX.xml
└── info.plist.TemplateiOS.xml
└── README.md
/Example/AndroidManifest.template.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
11 | <%uses-permission%>
12 |
13 |
21 |
22 | <%application-meta-data%>
23 | <%services%>
24 |
26 |
30 |
31 |
33 |
34 |
35 |
36 |
37 |
38 | <%activity%>
39 | <%receivers%>
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/Example/Bin/FastMM_FullDebugMode.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grijjy/DelphiPlatformTimerQueue/6a45dcafa79dffaa6a17c671e6ede385fce51deb/Example/Bin/FastMM_FullDebugMode.dll
--------------------------------------------------------------------------------
/Example/Bin/FastMM_FullDebugMode64.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grijjy/DelphiPlatformTimerQueue/6a45dcafa79dffaa6a17c671e6ede385fce51deb/Example/Bin/FastMM_FullDebugMode64.dll
--------------------------------------------------------------------------------
/Example/Entitlement.TemplateOSX32.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%appSandboxKeys%>
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Example/Entitlement.TemplateiOS.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%getTaskAllowKey%>
6 | <%applicationIdentifier%>
7 | <%pushNotificationKey%>
8 | <%keychainAccessGroups%>
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Example/FMain.fmx:
--------------------------------------------------------------------------------
1 | object FormMain: TFormMain
2 | Left = 0
3 | Top = 0
4 | Caption = 'Form8'
5 | ClientHeight = 628
6 | ClientWidth = 373
7 | FormFactor.Width = 320
8 | FormFactor.Height = 480
9 | FormFactor.Devices = [Desktop]
10 | OnCreate = FormCreate
11 | OnClose = FormClose
12 | DesignerMasterStyle = 0
13 | object EditTimers: TEdit
14 | Touch.InteractiveGestures = [LongTap, DoubleTap]
15 | TabOrder = 1
16 | Text = '1'
17 | Position.X = 16.000000000000000000
18 | Position.Y = 40.000000000000000000
19 | Size.Width = 57.000000000000000000
20 | Size.Height = 32.000000000000000000
21 | Size.PlatformDefault = False
22 | end
23 | object ButtonStart: TButton
24 | Position.X = 8.000000000000000000
25 | Position.Y = 96.000000000000000000
26 | Size.Width = 80.000000000000000000
27 | Size.Height = 25.000000000000000000
28 | Size.PlatformDefault = False
29 | TabOrder = 6
30 | Text = 'Start'
31 | OnClick = ButtonStartClick
32 | end
33 | object EditInterval: TEdit
34 | Touch.InteractiveGestures = [LongTap, DoubleTap]
35 | TabOrder = 0
36 | Text = '1000'
37 | Position.X = 88.000000000000000000
38 | Position.Y = 40.000000000000000000
39 | Size.Width = 81.000000000000000000
40 | Size.Height = 32.000000000000000000
41 | Size.PlatformDefault = False
42 | end
43 | object LabelTimers: TLabel
44 | Position.X = 16.000000000000000000
45 | Position.Y = 16.000000000000000000
46 | Size.Width = 57.000000000000000000
47 | Size.Height = 17.000000000000000000
48 | Size.PlatformDefault = False
49 | Text = 'Timers'
50 | TabOrder = 8
51 | end
52 | object LabelInterval: TLabel
53 | Position.X = 88.000000000000000000
54 | Position.Y = 16.000000000000000000
55 | Size.Width = 113.000000000000000000
56 | Size.Height = 17.000000000000000000
57 | Size.PlatformDefault = False
58 | Text = 'Interval (ms)'
59 | TabOrder = 7
60 | end
61 | object ButtonStopAll: TButton
62 | Position.X = 184.000000000000000000
63 | Position.Y = 96.000000000000000000
64 | Size.Width = 80.000000000000000000
65 | Size.Height = 25.000000000000000000
66 | Size.PlatformDefault = False
67 | TabOrder = 4
68 | Text = 'Stop All'
69 | OnClick = ButtonStopAllClick
70 | end
71 | object MemoLog: TMemo
72 | Touch.InteractiveGestures = [Pan, LongTap, DoubleTap]
73 | DataDetectorTypes = []
74 | Position.X = 8.000000000000000000
75 | Position.Y = 352.000000000000000000
76 | Size.Width = 353.000000000000000000
77 | Size.Height = 265.000000000000000000
78 | Size.PlatformDefault = False
79 | TabOrder = 10
80 | Viewport.Width = 349.000000000000000000
81 | Viewport.Height = 261.000000000000000000
82 | end
83 | object ListViewTimers: TListView
84 | ItemAppearanceClassName = 'TListItemAppearance'
85 | ItemEditAppearanceClassName = 'TListItemShowCheckAppearance'
86 | HeaderAppearanceClassName = 'TListHeaderObjects'
87 | FooterAppearanceClassName = 'TListHeaderObjects'
88 | Position.X = 8.000000000000000000
89 | Position.Y = 128.000000000000000000
90 | Size.Width = 353.000000000000000000
91 | Size.Height = 177.000000000000000000
92 | Size.PlatformDefault = False
93 | TabOrder = 9
94 | end
95 | object ButtonStop: TButton
96 | Position.X = 96.000000000000000000
97 | Position.Y = 96.000000000000000000
98 | Size.Width = 80.000000000000000000
99 | Size.Height = 25.000000000000000000
100 | Size.PlatformDefault = False
101 | TabOrder = 2
102 | Text = 'Stop'
103 | OnClick = ButtonStopClick
104 | end
105 | object ButtonClear: TButton
106 | Position.X = 8.000000000000000000
107 | Position.Y = 320.000000000000000000
108 | Size.Width = 80.000000000000000000
109 | Size.Height = 25.000000000000000000
110 | Size.PlatformDefault = False
111 | TabOrder = 5
112 | Text = 'Clear'
113 | OnClick = ButtonClearClick
114 | end
115 | object ButtonSetInterval: TButton
116 | Position.X = 272.000000000000000000
117 | Position.Y = 96.000000000000000000
118 | Size.Width = 80.000000000000000000
119 | Size.Height = 25.000000000000000000
120 | Size.PlatformDefault = False
121 | TabOrder = 3
122 | Text = 'Set Interval'
123 | OnClick = ButtonSetIntervalClick
124 | end
125 | end
126 |
--------------------------------------------------------------------------------
/Example/FMain.pas:
--------------------------------------------------------------------------------
1 | unit FMain;
2 |
3 | interface
4 |
5 | uses
6 | System.SysUtils,
7 | System.Types,
8 | System.UITypes,
9 | System.Classes,
10 | System.Variants,
11 | FMX.Types,
12 | FMX.Controls,
13 | FMX.Forms,
14 | FMX.Graphics,
15 | FMX.Dialogs,
16 | FMX.ScrollBox,
17 | FMX.Memo,
18 | FMX.StdCtrls,
19 | FMX.Controls.Presentation,
20 | FMX.Edit,
21 | FMX.ListView.Types,
22 | FMX.ListView.Appearances,
23 | FMX.ListView.Adapters.Base,
24 | FMX.ListView,
25 | System.Generics.Collections,
26 | Grijjy.TimerQueue;
27 |
28 | type
29 | TFormMain = class(TForm)
30 | EditTimers: TEdit;
31 | ButtonStart: TButton;
32 | EditInterval: TEdit;
33 | LabelTimers: TLabel;
34 | LabelInterval: TLabel;
35 | ButtonStopAll: TButton;
36 | MemoLog: TMemo;
37 | ListViewTimers: TListView;
38 | ButtonStop: TButton;
39 | ButtonClear: TButton;
40 | ButtonSetInterval: TButton;
41 | procedure FormCreate(Sender: TObject);
42 | procedure ButtonStartClick(Sender: TObject);
43 | procedure FormClose(Sender: TObject; var Action: TCloseAction);
44 | procedure ButtonStopAllClick(Sender: TObject);
45 | procedure ButtonStopClick(Sender: TObject);
46 | procedure ButtonClearClick(Sender: TObject);
47 | procedure ButtonSetIntervalClick(Sender: TObject);
48 | private
49 | { Private declarations }
50 | FTimerQueue: TgoTimerQueue;
51 |
52 | procedure OnTimer(const ASender: TObject);
53 | public
54 | { Public declarations }
55 | end;
56 |
57 | var
58 | FormMain: TFormMain;
59 |
60 | implementation
61 |
62 | {$R *.fmx}
63 |
64 | procedure TFormMain.FormCreate(Sender: TObject);
65 | begin
66 | FTimerQueue := TgoTimerQueue.Create;
67 | end;
68 |
69 | procedure TFormMain.FormClose(Sender: TObject; var Action: TCloseAction);
70 | begin
71 | FTimerQueue.Free;
72 | end;
73 |
74 | procedure TFormMain.ButtonStartClick(Sender: TObject);
75 | var
76 | Timers, Interval: Integer;
77 | Handle: THandle;
78 | I: Integer;
79 | Item: TListViewItem;
80 | begin
81 | Timers := StrToIntDef(EditTimers.Text, 1);
82 | Interval := StrToIntDef(EditInterval.Text, 1000);
83 |
84 | for I := 0 to Timers - 1 do
85 | begin
86 | Handle := FTimerQueue.Add(Interval, OnTimer);
87 | Item := ListViewTimers.Items.Add;
88 | Item.Tag := Handle;
89 | Item.Text := Format('Timer (%s, Interval=%d)',
90 | [UInt32(Handle).ToHexString, Interval]);
91 | end;
92 | end;
93 |
94 | procedure TFormMain.ButtonStopAllClick(Sender: TObject);
95 | var
96 | Handle: THandle;
97 | Item: TListViewItem;
98 | begin
99 | for Item in ListViewTimers.Items do
100 | begin
101 | Handle := Item.Tag;
102 | FTimerQueue.Release(Handle);
103 | end;
104 | ListViewTimers.Items.Clear;
105 | end;
106 |
107 | procedure TFormMain.ButtonStopClick(Sender: TObject);
108 | var
109 | Handle: THandle;
110 | begin
111 | if ListViewTimers.ItemIndex > -1 then
112 | begin
113 | Handle := ListViewTimers.Items[ListViewTimers.ItemIndex].Tag;
114 | FTimerQueue.Release(Handle);
115 | ListViewTimers.Items.Delete(ListViewTimers.ItemIndex);
116 | end;
117 | end;
118 |
119 | procedure TFormMain.ButtonSetIntervalClick(Sender: TObject);
120 | var
121 | Interval: Integer;
122 | Handle: THandle;
123 | begin
124 | Interval := StrToIntDef(EditInterval.Text, 1000);
125 |
126 | if ListViewTimers.ItemIndex > -1 then
127 | begin
128 | Handle := ListViewTimers.Items[ListViewTimers.ItemIndex].Tag;
129 | FTimerQueue.SetInterval(Handle, Interval);
130 | end;
131 | end;
132 |
133 | procedure TFormMain.ButtonClearClick(Sender: TObject);
134 | begin
135 | MemoLog.Lines.Clear;
136 | end;
137 |
138 | procedure TFormMain.OnTimer(const ASender: TObject);
139 | var
140 | S: String;
141 | Timer: TgoTimer;
142 | begin
143 | Timer := ASender as TgoTimer;
144 | S := (Format('OnTimer (%s, Thread=%s, Interval=%d)',
145 | [UInt32(Timer.Handle).ToHexString, TThread.CurrentThread.ThreadID.ToHexString, Timer.Interval]));
146 |
147 | TThread.Synchronize(nil,
148 | procedure
149 | begin
150 | MemoLog.Lines.Add(S);
151 | MemoLog.GoToTextEnd;
152 | end);
153 | end;
154 |
155 | end.
156 |
--------------------------------------------------------------------------------
/Example/ProjectTimerQueues.groupproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | {A1C7F860-A3A6-49E1-92EA-BF4B298703E7}
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | Default.Personality.12
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 |
--------------------------------------------------------------------------------
/Example/TimerQueues.deployproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 12
5 |
6 |
7 | 04241158012360049ddd
8 |
9 |
10 | iPhone5
11 |
12 |
13 |
14 | TimerQueues\
15 | TimerQueues.exe
16 | ProjectOutput
17 | 0
18 |
19 |
20 | True
21 | True
22 |
23 |
24 |
25 |
26 | TimerQueues.app\
27 | Info.plist
28 | ProjectiOSInfoPList
29 | 1
30 |
31 |
32 | True
33 |
34 |
35 | TimerQueues.app\
36 | Default-568h@2x.png
37 | iPhone_Launch640x1136
38 | 1
39 |
40 |
41 | True
42 |
43 |
44 | TimerQueues.app\
45 | FM_ApplicationIcon_180x180.png
46 | iPhone_AppIcon180
47 | 0
48 |
49 |
50 | True
51 |
52 |
53 | TimerQueues.app\
54 | FM_ApplicationIcon_57x57.png
55 | iPhone_AppIcon57
56 | 0
57 |
58 |
59 | True
60 |
61 |
62 | TimerQueues.app\
63 | FM_ApplicationIcon_144x144.png
64 | iPad_AppIcon144
65 | 0
66 |
67 |
68 | True
69 |
70 |
71 | TimerQueues.app\
72 | FM_ApplicationIcon_60x60.png
73 | iPhone_AppIcon60
74 | 0
75 |
76 |
77 | True
78 |
79 |
80 | TimerQueues.app\
81 | Default-667h@2x.png
82 | iPhone_Launch750
83 | 0
84 |
85 |
86 | True
87 |
88 |
89 | TimerQueues.app\
90 | FM_SettingIcon_29x29.png
91 | iPad_Setting29
92 | 0
93 |
94 |
95 | True
96 |
97 |
98 | TimerQueues.app\
99 | Default@2x.png
100 | iPhone_Launch640
101 | 1
102 |
103 |
104 | True
105 |
106 |
107 | TimerQueues.app\
108 | FM_SettingIcon_58x58.png
109 | iPad_Setting58
110 | 0
111 |
112 |
113 | True
114 |
115 |
116 | TimerQueues.app\
117 | Default.png
118 | iPhone_Launch320
119 | 1
120 |
121 |
122 | True
123 |
124 |
125 | TimerQueues.app\
126 | FM_ApplicationIcon_72x72.png
127 | iPad_AppIcon72
128 | 0
129 |
130 |
131 | True
132 |
133 |
134 | TimerQueues.app\
135 | Default-Portrait@2x.png
136 | iPad_Launch1536
137 | 1
138 |
139 |
140 | True
141 |
142 |
143 | TimerQueues.app\
144 | Default-Landscape@2x.png
145 | iPad_Launch2048
146 | 1
147 |
148 |
149 | True
150 |
151 |
152 | TimerQueues.app\
153 | FM_ApplicationIcon_120x120.png
154 | iPhone_AppIcon120
155 | 0
156 |
157 |
158 | True
159 |
160 |
161 | TimerQueues.app\
162 | Default-Portrait@2x~ipad.png
163 | iPad_Launch1536x2048
164 | 0
165 |
166 |
167 | True
168 |
169 |
170 | TimerQueues.app\
171 | FM_SpotlightSearchIcon_100x100.png
172 | iPad_SpotLight100
173 | 0
174 |
175 |
176 | True
177 |
178 |
179 | TimerQueues.app\
180 | FM_SpotlightSearchIcon_58x58.png
181 | iPhone_Spotlight58
182 | 0
183 |
184 |
185 | True
186 |
187 |
188 | TimerQueues.app\
189 | TimerQueues
190 | ProjectOutput
191 | 1
192 |
193 |
194 | True
195 | True
196 |
197 |
198 | TimerQueues.app\
199 | Default~ipad.png
200 | iPad_Launch768
201 | 1
202 |
203 |
204 | True
205 |
206 |
207 | TimerQueues.app\
208 | Default-Landscape-812h@3x.png
209 | iPhone_Launch2436
210 | 0
211 |
212 |
213 | True
214 |
215 |
216 | TimerQueues.app\..\
217 | TimerQueues.entitlements
218 | ProjectiOSEntitlements
219 | 1
220 |
221 |
222 | True
223 |
224 |
225 | TimerQueues.app\
226 | Default-Portrait~ipad.png
227 | iPad_Launch768x1024
228 | 0
229 |
230 |
231 | True
232 |
233 |
234 | TimerQueues.app\
235 | FM_ApplicationIcon_114x114.png
236 | iPhone_AppIcon114
237 | 0
238 |
239 |
240 | True
241 |
242 |
243 | TimerQueues.app\
244 | FM_SpotlightSearchIcon_50x50.png
245 | iPad_SpotLight50
246 | 0
247 |
248 |
249 | True
250 |
251 |
252 | TimerQueues.app\
253 | FM_ApplicationIcon_76x76.png
254 | iPad_AppIcon76
255 | 0
256 |
257 |
258 | True
259 |
260 |
261 | TimerQueues.app\
262 | FM_SpotlightSearchIcon_80x80.png
263 | iPhone_Spotlight80
264 | 0
265 |
266 |
267 | True
268 |
269 |
270 | TimerQueues.app\
271 | FM_SpotlightSearchIcon_80x80.png
272 | iPad_SpotLight80
273 | 0
274 |
275 |
276 | True
277 |
278 |
279 | TimerQueues.app\
280 | Default-Landscape-736h@3x.png
281 | iPhone_Launch2208
282 | 0
283 |
284 |
285 | True
286 |
287 |
288 | TimerQueues.app\..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF\
289 | TimerQueues
290 | ProjectiOSDeviceDebug
291 | 1
292 |
293 |
294 | True
295 |
296 |
297 | TimerQueues.app\
298 | FM_SpotlightSearchIcon_40x40.png
299 | iPhone_Spotlight40
300 | 0
301 |
302 |
303 | True
304 |
305 |
306 | TimerQueues.app\
307 | Default-736h@3x.png
308 | iPhone_Launch1242
309 | 0
310 |
311 |
312 | True
313 |
314 |
315 | TimerQueues.app\
316 | Default-812h@3x.png
317 | iPhone_Launch1125
318 | 0
319 |
320 |
321 | True
322 |
323 |
324 | TimerQueues.app\
325 | Default-Landscape.png
326 | iPad_Launch1024
327 | 1
328 |
329 |
330 | True
331 |
332 |
333 | TimerQueues.app\
334 | FM_ApplicationIcon_152x152.png
335 | iPad_AppIcon152
336 | 0
337 |
338 |
339 | True
340 |
341 |
342 | TimerQueues.app\
343 | FM_SpotlightSearchIcon_40x40.png
344 | iPad_SpotLight40
345 | 0
346 |
347 |
348 | True
349 |
350 |
351 | TimerQueues.app\
352 | FM_ApplicationIcon_87x87.png
353 | iPhone_AppIcon87
354 | 0
355 |
356 |
357 | True
358 |
359 |
360 | TimerQueues.app\
361 | FM_SpotlightSearchIcon_29x29.png
362 | iPhone_Spotlight29
363 | 0
364 |
365 |
366 | True
367 |
368 |
369 | TimerQueues.app\
370 | ResourceRules.plist
371 | ProjectiOSDeviceResourceRules
372 | 1
373 |
374 |
375 | True
376 |
377 |
378 | TimerQueues.app\
379 | Default-Landscape@2x~ipad.png
380 | iPad_Launch2048x1536
381 | 0
382 |
383 |
384 | True
385 |
386 |
387 | TimerQueues.app\
388 | Default-Landscape~ipad.png
389 | iPad_Launch1024x768
390 | 0
391 |
392 |
393 | True
394 |
395 |
396 |
397 |
398 |
399 | TimerQueues\
400 | TimerQueues.exe
401 | ProjectOutput
402 | 0
403 |
404 |
405 | True
406 | True
407 |
408 |
409 |
410 |
411 |
412 | TimerQueues.app\Contents\Resources\StartUp\
413 | libzmq-osx32.dylib
414 | File
415 | 0
416 |
417 |
418 | True
419 |
420 |
421 | TimerQueues.app\Contents\MacOS\
422 | TimerQueues
423 | ProjectOutput
424 | 1
425 |
426 |
427 | True
428 | True
429 |
430 |
431 | TimerQueues.app\Contents\
432 | Info.plist
433 | ProjectOSXInfoPList
434 | 1
435 |
436 |
437 | True
438 |
439 |
440 | TimerQueues.app\Contents\Resources\
441 | TimerQueues.icns
442 | ProjectOSXResource
443 | 1
444 |
445 |
446 | True
447 |
448 |
449 | TimerQueues.app\Contents\MacOS\
450 | libcgsqlite3.dylib
451 | DependencyModule
452 | 1
453 |
454 |
455 | True
456 |
457 |
458 | TimerQueues.app\..\
459 | TimerQueues.entitlements
460 | ProjectOSXEntitlements
461 | 1
462 |
463 |
464 | True
465 |
466 |
467 | TimerQueues.app\Contents\MacOS\
468 | libcgunwind.1.0.dylib
469 | DependencyModule
470 | 1
471 |
472 |
473 | True
474 |
475 |
476 | TimerQueues.app\Contents\MacOS\
477 | libzmq-osx32.dylib
478 | File
479 | 0
480 |
481 |
482 | True
483 |
484 |
485 |
486 |
487 | TimerQueues\res\drawable-ldpi\
488 | ic_launcher.png
489 | Android_LauncherIcon36
490 | 1
491 |
492 |
493 | True
494 |
495 |
496 | TimerQueues\res\drawable-hdpi\
497 | ic_launcher.png
498 | Android_LauncherIcon72
499 | 1
500 |
501 |
502 | True
503 |
504 |
505 | TimerQueues\res\drawable-small\
506 | splash_image.png
507 | Android_SplashImage426
508 | 1
509 |
510 |
511 | True
512 |
513 |
514 | TimerQueues\library\lib\mips\
515 | libTimerQueues.so
516 | AndroidLibnativeMipsFile
517 | 1
518 |
519 |
520 | True
521 |
522 |
523 | TimerQueues\res\drawable\
524 | splash_image_def.xml
525 | AndroidSplashImageDef
526 | 1
527 |
528 |
529 | True
530 |
531 |
532 | TimerQueues\
533 | AndroidManifest.xml
534 | ProjectAndroidManifest
535 | 1
536 |
537 |
538 | True
539 |
540 |
541 | TimerQueues\library\lib\armeabi\
542 | libTimerQueues.so
543 | AndroidLibnativeArmeabiFile
544 | 1
545 |
546 |
547 | True
548 |
549 |
550 | TimerQueues\res\drawable-xxhdpi\
551 | ic_launcher.png
552 | Android_LauncherIcon144
553 | 1
554 |
555 |
556 | True
557 |
558 |
559 | TimerQueues\res\drawable-xhdpi\
560 | ic_launcher.png
561 | Android_LauncherIcon96
562 | 1
563 |
564 |
565 | True
566 |
567 |
568 | TimerQueues\res\drawable-large\
569 | splash_image.png
570 | Android_SplashImage640
571 | 1
572 |
573 |
574 | True
575 |
576 |
577 | TimerQueues\res\drawable-xlarge\
578 | splash_image.png
579 | Android_SplashImage960
580 | 1
581 |
582 |
583 | True
584 |
585 |
586 | TimerQueues\res\drawable-mdpi\
587 | ic_launcher.png
588 | Android_LauncherIcon48
589 | 1
590 |
591 |
592 | True
593 |
594 |
595 | TimerQueues\library\lib\armeabi-v7a\
596 | gdbserver
597 | AndroidGDBServer
598 | 1
599 |
600 |
601 | True
602 |
603 |
604 | TimerQueues\classes\
605 | classes.dex
606 | AndroidClassesDexFile
607 | 1
608 |
609 |
610 | True
611 |
612 |
613 | TimerQueues\res\values\
614 | styles.xml
615 | AndroidSplashStyles
616 | 1
617 |
618 |
619 | True
620 |
621 |
622 | TimerQueues\library\lib\armeabi-v7a\
623 | libTimerQueues.so
624 | ProjectOutput
625 | 1
626 |
627 |
628 | True
629 | True
630 |
631 |
632 | TimerQueues\res\drawable-normal\
633 | splash_image.png
634 | Android_SplashImage470
635 | 1
636 |
637 |
638 | True
639 |
640 |
641 |
642 |
643 | TimerQueues.app\
644 | libcgunwind.1.0.dylib
645 | DependencyModule
646 | 1
647 |
648 |
649 | True
650 |
651 |
652 | TimerQueues.app\
653 | libPCRE.dylib
654 | DependencyModule
655 | 1
656 |
657 |
658 | True
659 |
660 |
661 |
662 |
--------------------------------------------------------------------------------
/Example/TimerQueues.dpr:
--------------------------------------------------------------------------------
1 | program TimerQueues;
2 |
3 | uses
4 | System.StartUpCopy,
5 | FMX.Forms,
6 | FMain in 'FMain.pas' {FormMain};
7 |
8 | {$R *.res}
9 |
10 | begin
11 | ReportMemoryLeaksOnShutDown := True;
12 |
13 | Application.Initialize;
14 | Application.CreateForm(TFormMain, FormMain);
15 | Application.Run;
16 | end.
17 |
--------------------------------------------------------------------------------
/Example/TimerQueues.dproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | {5410AA92-BDC3-48FA-8463-B0E857819928}
4 | 18.4
5 | FMX
6 | TimerQueues.dpr
7 | True
8 | Debug
9 | Win64
10 | 1119
11 | Application
12 |
13 |
14 | true
15 |
16 |
17 | true
18 | Base
19 | true
20 |
21 |
22 | true
23 | Base
24 | true
25 |
26 |
27 | true
28 | Base
29 | true
30 |
31 |
32 | true
33 | Base
34 | true
35 |
36 |
37 | true
38 | Base
39 | true
40 |
41 |
42 | true
43 | Base
44 | true
45 |
46 |
47 | true
48 | Base
49 | true
50 |
51 |
52 | true
53 | Base
54 | true
55 |
56 |
57 | true
58 | Cfg_1
59 | true
60 | true
61 |
62 |
63 | true
64 | Cfg_1
65 | true
66 | true
67 |
68 |
69 | true
70 | Cfg_1
71 | true
72 | true
73 |
74 |
75 | true
76 | Base
77 | true
78 |
79 |
80 | true
81 | Cfg_2
82 | true
83 | true
84 |
85 |
86 | true
87 | Cfg_2
88 | true
89 | true
90 |
91 |
92 | .\$(Platform)\$(Config)
93 | .\$(Platform)\$(Config)
94 | false
95 | false
96 | false
97 | false
98 | false
99 | RESTComponents;emsclientfiredac;DataSnapFireDAC;FireDACIBDriver;emsclient;FireDACCommon;RESTBackendComponents;soapserver;CloudService;FireDACCommonDriver;inet;FireDAC;FireDACSqliteDriver;soaprtl;soapmidas;$(DCC_UsePackage)
100 | System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)
101 | true
102 | true
103 | true
104 | true
105 | true
106 | true
107 | true
108 | true
109 | true
110 | true
111 | $(BDS)\bin\delphi_PROJECTICON.ico
112 | $(BDS)\bin\delphi_PROJECTICNS.icns
113 | TimerQueues
114 | ..\..\GrijjyFoundation;$(DCC_UnitSearchPath)
115 |
116 |
117 | DBXSqliteDriver;DBXInterBaseDriver;tethering;bindcompfmx;fmx;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;bindengine;DataSnapClient;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;DbxCommonDriver;xmlrtl;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)
118 | package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=
119 | Debug
120 | true
121 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png
122 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png
123 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png
124 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png
125 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png
126 | $(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png
127 | $(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png
128 | $(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png
129 | $(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png
130 | android-support-v4.dex.jar;cloud-messaging.dex.jar;fmx.dex.jar;google-analytics-v2.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar;google-play-services-ads-7.0.0.dex.jar;google-play-services-analytics-7.0.0.dex.jar;google-play-services-base-7.0.0.dex.jar;google-play-services-identity-7.0.0.dex.jar;google-play-services-maps-7.0.0.dex.jar;google-play-services-panorama-7.0.0.dex.jar;google-play-services-plus-7.0.0.dex.jar;google-play-services-wallet-7.0.0.dex.jar
131 |
132 |
133 | DBXSqliteDriver;fmxase;DBXInterBaseDriver;tethering;bindcompfmx;fmx;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;bindengine;DataSnapClient;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;DbxCommonDriver;xmlrtl;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)
134 | CFBundleName=$(MSBuildProjectName);CFBundleDevelopmentRegion=en;CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleInfoDictionaryVersion=7.1;CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;LSRequiresIPhoneOS=true;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);UIDeviceFamily=iPhone & iPad;CFBundleResourceSpecification=ResourceRules.plist;NSLocationAlwaysUsageDescription=The reason for accessing the location information of the user;NSLocationWhenInUseUsageDescription=The reason for accessing the location information of the user;FMLocalNotificationPermission=false;UIBackgroundModes=;NSContactsUsageDescription=The reason for accessing the contacts;NSPhotoLibraryUsageDescription=The reason for accessing the photo library;NSCameraUsageDescription=The reason for accessing the camera
135 | iPhoneAndiPad
136 | true
137 | Debug
138 | $(MSBuildProjectName)
139 | $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_57x57.png
140 | $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_60x60.png
141 | $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_87x87.png
142 | $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_114x114.png
143 | $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png
144 | $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_180x180.png
145 | $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_320x480.png
146 | $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_640x960.png
147 | $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_640x1136.png
148 | $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_750x1334.png
149 | $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_1242x2208.png
150 | $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_2208x1242.png
151 | $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_1125x2436.png
152 | $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_2436x1125.png
153 | $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_29x29.png
154 | $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_40x40.png
155 | $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_58x58.png
156 | $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png
157 | $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_72x72.png
158 | $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_76x76.png
159 | $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_144x144.png
160 | $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png
161 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_768x1004.png
162 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_768x1024.png
163 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_1024x748.png
164 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_1024x768.png
165 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_1536x2008.png
166 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_1536x2048.png
167 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_2048x1496.png
168 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_2048x1536.png
169 | $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_40x40.png
170 | $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_50x50.png
171 | $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png
172 | $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_100x100.png
173 | $(BDS)\bin\Artwork\iOS\iPad\FM_SettingIcon_29x29.png
174 | $(BDS)\bin\Artwork\iOS\iPad\FM_SettingIcon_58x58.png
175 |
176 |
177 | DBXSqliteDriver;fmxase;DBXInterBaseDriver;tethering;bindcompfmx;fmx;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;bindengine;DataSnapClient;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;DbxCommonDriver;xmlrtl;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)
178 | CFBundleName=$(MSBuildProjectName);CFBundleDevelopmentRegion=en;CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleInfoDictionaryVersion=7.1;CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;LSRequiresIPhoneOS=true;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);UIDeviceFamily=iPhone & iPad;CFBundleResourceSpecification=ResourceRules.plist;NSLocationAlwaysUsageDescription=The reason for accessing the location information of the user;NSLocationWhenInUseUsageDescription=The reason for accessing the location information of the user;FMLocalNotificationPermission=false;UIBackgroundModes=;NSContactsUsageDescription=The reason for accessing the contacts;NSPhotoLibraryUsageDescription=The reason for accessing the photo library;NSCameraUsageDescription=The reason for accessing the camera
179 | iPhoneAndiPad
180 | true
181 | Debug
182 | $(MSBuildProjectName)
183 | $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_57x57.png
184 | $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_60x60.png
185 | $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_87x87.png
186 | $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_114x114.png
187 | $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png
188 | $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_180x180.png
189 | $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_320x480.png
190 | $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_640x960.png
191 | $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_640x1136.png
192 | $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_750x1334.png
193 | $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_1242x2208.png
194 | $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_2208x1242.png
195 | $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_1125x2436.png
196 | $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_2436x1125.png
197 | $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_29x29.png
198 | $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_40x40.png
199 | $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_58x58.png
200 | $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png
201 | $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_72x72.png
202 | $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_76x76.png
203 | $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_144x144.png
204 | $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png
205 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_768x1004.png
206 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_768x1024.png
207 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_1024x748.png
208 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_1024x768.png
209 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_1536x2008.png
210 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_1536x2048.png
211 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_2048x1496.png
212 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_2048x1536.png
213 | $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_40x40.png
214 | $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_50x50.png
215 | $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png
216 | $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_100x100.png
217 | $(BDS)\bin\Artwork\iOS\iPad\FM_SettingIcon_29x29.png
218 | $(BDS)\bin\Artwork\iOS\iPad\FM_SettingIcon_58x58.png
219 |
220 |
221 | DBXSqliteDriver;fmxase;DBXInterBaseDriver;tethering;bindcompfmx;fmx;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;bindengine;DataSnapClient;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;DbxCommonDriver;xmlrtl;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)
222 | CFBundleName=$(MSBuildProjectName);CFBundleDevelopmentRegion=en;CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleInfoDictionaryVersion=7.1;CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;LSRequiresIPhoneOS=true;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);UIDeviceFamily=iPhone & iPad;CFBundleResourceSpecification=ResourceRules.plist;NSLocationAlwaysUsageDescription=The reason for accessing the location information of the user;NSLocationWhenInUseUsageDescription=The reason for accessing the location information of the user;FMLocalNotificationPermission=false;UIBackgroundModes=;NSContactsUsageDescription=The reason for accessing the contacts;NSPhotoLibraryUsageDescription=The reason for accessing the photo library;NSCameraUsageDescription=The reason for accessing the camera
223 | iPhoneAndiPad
224 | true
225 | $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_57x57.png
226 | $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_60x60.png
227 | $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_87x87.png
228 | $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_114x114.png
229 | $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png
230 | $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_180x180.png
231 | $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_320x480.png
232 | $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_640x960.png
233 | $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_640x1136.png
234 | $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_750x1334.png
235 | $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_1242x2208.png
236 | $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_2208x1242.png
237 | $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_1125x2436.png
238 | $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_2436x1125.png
239 | $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_29x29.png
240 | $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_40x40.png
241 | $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_58x58.png
242 | $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png
243 | $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_72x72.png
244 | $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_76x76.png
245 | $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_144x144.png
246 | $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png
247 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_768x1004.png
248 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_768x1024.png
249 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_1024x748.png
250 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_1024x768.png
251 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_1536x2008.png
252 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_1536x2048.png
253 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_2048x1496.png
254 | $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_2048x1536.png
255 | $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_40x40.png
256 | $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_50x50.png
257 | $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png
258 | $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_100x100.png
259 | $(BDS)\bin\Artwork\iOS\iPad\FM_SettingIcon_29x29.png
260 | $(BDS)\bin\Artwork\iOS\iPad\FM_SettingIcon_58x58.png
261 |
262 |
263 | DBXSqliteDriver;fmxase;DBXInterBaseDriver;tethering;FireDACMSSQLDriver;bindcompfmx;DBXOracleDriver;inetdb;emsedge;fmx;fmxdae;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;bindengine;DBXMySQLDriver;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;DataSnapClient;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;emshosting;FireDACPgDriver;FireDACASADriver;FireDACTDataDriver;DbxCommonDriver;DataSnapServer;xmlrtl;DataSnapNativeClient;fmxobj;FireDACDSDriver;rtl;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;bindcomp;DBXInformixDriver;IndyIPClient;dbxcds;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;DataSnapServerMidas;$(DCC_UsePackage)
264 | CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationAlwaysUsageDescription=The reason for accessing the location information of the user;NSLocationWhenInUseUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts
265 | Debug
266 | true
267 |
268 |
269 | DBXSqliteDriver;fmxase;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;tethering;svnui;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;svn;DBXOracleDriver;inetdb;emsedge;fmx;fmxdae;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;DataSnapCommon;DataSnapConnectors;VCLRESTComponents;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;Grijjy.Package.RTL;FireDACCommonODBC;DataSnapClient;IndyIPCommon;bindcompdbx;TMSListControlsDXE11;vcl;IndyIPServer;DBXSybaseASEDriver;IndySystem;FireDACDb2Driver;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;emshosting;FireDACPgDriver;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;DbxCommonDriver;DataSnapServer;xmlrtl;DataSnapNativeClient;fmxobj;vclwinx;FireDACDSDriver;rtl;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;Grijjy.Package.FMX;DataSnapServerMidas;$(DCC_UsePackage)
270 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
271 | Debug
272 | true
273 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=
274 | 1033
275 | $(BDS)\bin\default_app.manifest
276 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png
277 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png
278 | .\Bin
279 |
280 |
281 | DBXSqliteDriver;fmxase;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;tethering;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;DBXOracleDriver;inetdb;emsedge;fmx;fmxdae;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;DataSnapCommon;DataSnapConnectors;VCLRESTComponents;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;DataSnapClient;IndyIPCommon;bindcompdbx;vcl;IndyIPServer;DBXSybaseASEDriver;IndySystem;FireDACDb2Driver;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;emshosting;FireDACPgDriver;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;DbxCommonDriver;DataSnapServer;xmlrtl;DataSnapNativeClient;fmxobj;vclwinx;FireDACDSDriver;rtl;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;DataSnapServerMidas;$(DCC_UsePackage)
282 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)
283 | Debug
284 | true
285 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=
286 | 1033
287 | $(BDS)\bin\default_app.manifest
288 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png
289 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png
290 | .\Bin
291 |
292 |
293 | DEBUG;$(DCC_Define)
294 | true
295 | false
296 | true
297 | true
298 | true
299 |
300 |
301 | true
302 | iPhoneAndiPad
303 | $(MSBuildProjectName)
304 |
305 |
306 | false
307 | true
308 | true
309 | true
310 | 1033
311 |
312 |
313 | true
314 | true
315 | true
316 | 1033
317 |
318 |
319 | false
320 | RELEASE;$(DCC_Define)
321 | 0
322 | 0
323 |
324 |
325 | true
326 | true
327 |
328 |
329 | true
330 | true
331 |
332 |
333 |
334 | MainSource
335 |
336 |
337 |
338 | fmx
339 |
340 |
341 | Cfg_2
342 | Base
343 |
344 |
345 | Base
346 |
347 |
348 | Cfg_1
349 | Base
350 |
351 |
352 |
353 | Delphi.Personality.12
354 | Application
355 |
356 |
357 |
358 | TimerQueues.dpr
359 |
360 |
361 | Microsoft Office 2000 Sample Automation Server Wrapper Components
362 | Microsoft Office XP Sample Automation Server Wrapper Components
363 |
364 |
365 |
366 |
367 |
368 | ic_launcher.png
369 | true
370 |
371 |
372 |
373 |
374 | Info.plist
375 | true
376 |
377 |
378 |
379 |
380 | ic_launcher.png
381 | true
382 |
383 |
384 |
385 |
386 | Default-568h@2x.png
387 | true
388 |
389 |
390 |
391 |
392 | true
393 |
394 |
395 |
396 |
397 | true
398 |
399 |
400 |
401 |
402 | true
403 |
404 |
405 |
406 |
407 | splash_image.png
408 | true
409 |
410 |
411 |
412 |
413 | libzmq-osx32.dylib
414 | true
415 |
416 |
417 |
418 |
419 | true
420 |
421 |
422 |
423 |
424 | Default-667h@2x.png
425 | true
426 |
427 |
428 |
429 |
430 | libTimerQueues.so
431 | true
432 |
433 |
434 |
435 |
436 | true
437 |
438 |
439 |
440 |
441 | true
442 |
443 |
444 |
445 |
446 | TimerQueues
447 | true
448 |
449 |
450 |
451 |
452 | Default@2x.png
453 | true
454 |
455 |
456 |
457 |
458 | TimerQueues.exe
459 | true
460 |
461 |
462 |
463 |
464 | Info.plist
465 | true
466 |
467 |
468 |
469 |
470 | true
471 |
472 |
473 |
474 |
475 | true
476 |
477 |
478 |
479 |
480 | libTimerQueues.so
481 | true
482 |
483 |
484 |
485 |
486 | ic_launcher.png
487 | true
488 |
489 |
490 |
491 |
492 | true
493 |
494 |
495 |
496 |
497 | TimerQueues.icns
498 | true
499 |
500 |
501 |
502 |
503 | true
504 |
505 |
506 |
507 |
508 | true
509 |
510 |
511 |
512 |
513 | Default.png
514 | true
515 |
516 |
517 |
518 |
519 | true
520 |
521 |
522 |
523 |
524 | Default-Portrait@2x.png
525 | true
526 |
527 |
528 |
529 |
530 | true
531 |
532 |
533 |
534 |
535 | ic_launcher.png
536 | true
537 |
538 |
539 |
540 |
541 | Default-Landscape@2x.png
542 | true
543 |
544 |
545 |
546 |
547 | TimerQueues.exe
548 | true
549 |
550 |
551 |
552 |
553 | true
554 |
555 |
556 |
557 |
558 | Default-Portrait@2x~ipad.png
559 | true
560 |
561 |
562 |
563 |
564 | TimerQueues.rsm
565 | true
566 |
567 |
568 |
569 |
570 | true
571 |
572 |
573 |
574 |
575 | true
576 |
577 |
578 |
579 |
580 | TimerQueues
581 | true
582 |
583 |
584 |
585 |
586 | Default~ipad.png
587 | true
588 |
589 |
590 |
591 |
592 | Default-Landscape-812h@3x.png
593 | true
594 |
595 |
596 |
597 |
598 | true
599 |
600 |
601 |
602 |
603 | Default-Portrait~ipad.png
604 | true
605 |
606 |
607 |
608 |
609 | splash_image.png
610 | true
611 |
612 |
613 |
614 |
615 | splash_image.png
616 | true
617 |
618 |
619 |
620 |
621 | true
622 |
623 |
624 |
625 |
626 | true
627 |
628 |
629 |
630 |
631 | true
632 |
633 |
634 |
635 |
636 | true
637 |
638 |
639 |
640 |
641 | true
642 |
643 |
644 |
645 |
646 | ic_launcher.png
647 | true
648 |
649 |
650 |
651 |
652 | true
653 |
654 |
655 |
656 |
657 | Default-Landscape-736h@3x.png
658 | true
659 |
660 |
661 |
662 |
663 | true
664 |
665 |
666 |
667 |
668 | classes.dex
669 | true
670 |
671 |
672 |
673 |
674 | TimerQueues
675 | true
676 |
677 |
678 |
679 |
680 | true
681 |
682 |
683 |
684 |
685 | true
686 |
687 |
688 |
689 |
690 | Default-736h@3x.png
691 | true
692 |
693 |
694 |
695 |
696 | libTimerQueues.so
697 | true
698 |
699 |
700 |
701 |
702 | splash_image.png
703 | true
704 |
705 |
706 |
707 |
708 | Default-812h@3x.png
709 | true
710 |
711 |
712 |
713 |
714 | Default-Landscape.png
715 | true
716 |
717 |
718 |
719 |
720 | true
721 |
722 |
723 |
724 |
725 | true
726 |
727 |
728 |
729 |
730 | true
731 |
732 |
733 |
734 |
735 | true
736 |
737 |
738 |
739 |
740 | ResourceRules.plist
741 | true
742 |
743 |
744 |
745 |
746 | Default-Landscape@2x~ipad.png
747 | true
748 |
749 |
750 |
751 |
752 | Default-Landscape~ipad.png
753 | true
754 |
755 |
756 |
757 |
758 | Contents\MacOS\
759 | libzmq-osx32.dylib
760 | true
761 |
762 |
763 |
764 |
765 | 1
766 |
767 |
768 | Contents\MacOS
769 | 1
770 |
771 |
772 | Contents\MacOS
773 | 0
774 |
775 |
776 |
777 |
778 | classes
779 | 1
780 |
781 |
782 |
783 |
784 | library\lib\armeabi-v7a
785 | 1
786 |
787 |
788 |
789 |
790 | library\lib\armeabi
791 | 1
792 |
793 |
794 |
795 |
796 | library\lib\mips
797 | 1
798 |
799 |
800 |
801 |
802 | library\lib\armeabi-v7a
803 | 1
804 |
805 |
806 |
807 |
808 | res\drawable
809 | 1
810 |
811 |
812 |
813 |
814 | res\values
815 | 1
816 |
817 |
818 |
819 |
820 | res\drawable
821 | 1
822 |
823 |
824 |
825 |
826 | res\drawable-xxhdpi
827 | 1
828 |
829 |
830 |
831 |
832 | res\drawable-ldpi
833 | 1
834 |
835 |
836 |
837 |
838 | res\drawable-mdpi
839 | 1
840 |
841 |
842 |
843 |
844 | res\drawable-hdpi
845 | 1
846 |
847 |
848 |
849 |
850 | res\drawable-xhdpi
851 | 1
852 |
853 |
854 |
855 |
856 | res\drawable-small
857 | 1
858 |
859 |
860 |
861 |
862 | res\drawable-normal
863 | 1
864 |
865 |
866 |
867 |
868 | res\drawable-large
869 | 1
870 |
871 |
872 |
873 |
874 | res\drawable-xlarge
875 | 1
876 |
877 |
878 |
879 |
880 | 1
881 |
882 |
883 | Contents\MacOS
884 | 1
885 |
886 |
887 | 0
888 |
889 |
890 |
891 |
892 | Contents\MacOS
893 | 1
894 | .framework
895 |
896 |
897 | 0
898 |
899 |
900 |
901 |
902 | 1
903 | .dylib
904 |
905 |
906 | 1
907 | .dylib
908 |
909 |
910 | 1
911 | .dylib
912 |
913 |
914 | Contents\MacOS
915 | 1
916 | .dylib
917 |
918 |
919 | 0
920 | .dll;.bpl
921 |
922 |
923 |
924 |
925 | 1
926 | .dylib
927 |
928 |
929 | 1
930 | .dylib
931 |
932 |
933 | 1
934 | .dylib
935 |
936 |
937 | Contents\MacOS
938 | 1
939 | .dylib
940 |
941 |
942 | 0
943 | .bpl
944 |
945 |
946 |
947 |
948 | 0
949 |
950 |
951 | 0
952 |
953 |
954 | 0
955 |
956 |
957 | 0
958 |
959 |
960 | Contents\Resources\StartUp\
961 | 0
962 |
963 |
964 | 0
965 |
966 |
967 |
968 |
969 | 1
970 |
971 |
972 | 1
973 |
974 |
975 | 1
976 |
977 |
978 |
979 |
980 | 1
981 |
982 |
983 | 1
984 |
985 |
986 | 1
987 |
988 |
989 |
990 |
991 | 1
992 |
993 |
994 | 1
995 |
996 |
997 | 1
998 |
999 |
1000 |
1001 |
1002 | 1
1003 |
1004 |
1005 | 1
1006 |
1007 |
1008 | 1
1009 |
1010 |
1011 |
1012 |
1013 | 1
1014 |
1015 |
1016 | 1
1017 |
1018 |
1019 | 1
1020 |
1021 |
1022 |
1023 |
1024 | 1
1025 |
1026 |
1027 | 1
1028 |
1029 |
1030 | 1
1031 |
1032 |
1033 |
1034 |
1035 | 1
1036 |
1037 |
1038 | 1
1039 |
1040 |
1041 | 1
1042 |
1043 |
1044 |
1045 |
1046 | 1
1047 |
1048 |
1049 |
1050 |
1051 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
1052 | 1
1053 |
1054 |
1055 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
1056 | 1
1057 |
1058 |
1059 |
1060 |
1061 | 1
1062 |
1063 |
1064 | 1
1065 |
1066 |
1067 |
1068 |
1069 | ..\
1070 | 1
1071 |
1072 |
1073 | ..\
1074 | 1
1075 |
1076 |
1077 |
1078 |
1079 | 1
1080 |
1081 |
1082 | 1
1083 |
1084 |
1085 | 1
1086 |
1087 |
1088 |
1089 |
1090 | 1
1091 |
1092 |
1093 | 1
1094 |
1095 |
1096 | 1
1097 |
1098 |
1099 |
1100 |
1101 | ..\
1102 | 1
1103 |
1104 |
1105 |
1106 |
1107 | Contents
1108 | 1
1109 |
1110 |
1111 |
1112 |
1113 | Contents\Resources
1114 | 1
1115 |
1116 |
1117 |
1118 |
1119 | library\lib\armeabi-v7a
1120 | 1
1121 |
1122 |
1123 | 1
1124 |
1125 |
1126 | 1
1127 |
1128 |
1129 | 1
1130 |
1131 |
1132 | 1
1133 |
1134 |
1135 | Contents\MacOS
1136 | 1
1137 |
1138 |
1139 | 0
1140 |
1141 |
1142 |
1143 |
1144 | 1
1145 |
1146 |
1147 | 1
1148 |
1149 |
1150 |
1151 |
1152 | Assets
1153 | 1
1154 |
1155 |
1156 | Assets
1157 | 1
1158 |
1159 |
1160 |
1161 |
1162 | Assets
1163 | 1
1164 |
1165 |
1166 | Assets
1167 | 1
1168 |
1169 |
1170 |
1171 |
1172 |
1173 |
1174 |
1175 |
1176 |
1177 |
1178 |
1179 |
1180 | True
1181 | True
1182 | True
1183 | True
1184 | True
1185 | True
1186 | True
1187 |
1188 |
1189 | 12
1190 |
1191 |
1192 |
1193 |
1194 |
1195 |
--------------------------------------------------------------------------------
/Example/TimerQueues.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grijjy/DelphiPlatformTimerQueue/6a45dcafa79dffaa6a17c671e6ede385fce51deb/Example/TimerQueues.res
--------------------------------------------------------------------------------
/Example/TimerQueuesConsole.deployproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 12
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | TimerQueuesConsole\
18 | TimerQueuesConsole.exe
19 | ProjectOutput
20 | 0
21 |
22 |
23 | True
24 | True
25 |
26 |
27 |
28 |
29 | TimerQueuesConsole\
30 | libzmq-linux64.so
31 | File
32 | 0
33 |
34 |
35 | True
36 |
37 |
38 | TimerQueuesConsole\
39 | libzmq-linux64.so
40 | File
41 | 0
42 |
43 |
44 | True
45 |
46 |
47 | TimerQueuesConsole\
48 | TimerQueuesConsole
49 | ProjectOutput
50 | 1
51 |
52 |
53 | True
54 | True
55 |
56 |
57 |
58 |
59 | TimerQueuesConsole.app\Contents\MacOS\
60 | libcgunwind.1.0.dylib
61 | DependencyModule
62 | 1
63 |
64 |
65 | True
66 |
67 |
68 | TimerQueuesConsole.app\Contents\MacOS\
69 | libcgsqlite3.dylib
70 | DependencyModule
71 | 1
72 |
73 |
74 | True
75 |
76 |
77 |
78 |
79 |
80 | TimerQueuesConsole.app\
81 | libPCRE.dylib
82 | DependencyModule
83 | 1
84 |
85 |
86 | True
87 |
88 |
89 | TimerQueuesConsole.app\
90 | libcgunwind.1.0.dylib
91 | DependencyModule
92 | 1
93 |
94 |
95 | True
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/Example/TimerQueuesConsole.dpr:
--------------------------------------------------------------------------------
1 | program TimerQueuesConsole;
2 |
3 | {$APPTYPE CONSOLE}
4 |
5 | {$R *.res}
6 |
7 | uses
8 | System.SysUtils,
9 | System.Classes,
10 | Grijjy.TimerQueue;
11 |
12 | type
13 | TMyClass = class
14 | procedure OnTimer(const ASender: TObject);
15 | end;
16 |
17 | var
18 | TimerQueue: TgoTimerQueue;
19 | MyClass: TMyClass;
20 |
21 | { TMyClass }
22 |
23 | procedure TMyClass.OnTimer(const ASender: TObject);
24 | var
25 | S: String;
26 | Timer: TgoTimer;
27 | begin
28 | Timer := ASender as TgoTimer;
29 | S := (Format('OnTimer (%s, Thread=%s, Interval=%d)',
30 | [UInt32(Timer.Handle).ToHexString, TThread.CurrentThread.ThreadID.ToHexString, Timer.Interval]));
31 |
32 | Writeln(S); // The console is not thread safe
33 | end;
34 |
35 | begin
36 | ReportMemoryLeaksOnShutDown := True;
37 |
38 | try
39 | TimerQueue := TgoTimerQueue.Create;
40 | try
41 | MyClass := TMyClass.Create;
42 | try
43 | TimerQueue.Add(1000, MyClass.OnTimer);
44 | TimerQueue.Add(500, MyClass.OnTimer);
45 | TimerQueue.Add(100, MyClass.OnTimer);
46 |
47 | Readln;
48 | finally
49 | MyClass.Free;
50 | end;
51 | finally
52 | TimerQueue.Free;
53 | end;
54 | except
55 | on E: Exception do
56 | Writeln(E.ClassName, ': ', E.Message);
57 | end;
58 | end.
59 |
--------------------------------------------------------------------------------
/Example/TimerQueuesConsole.dproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | {D4EEB2CF-EF1B-4574-BF0C-1D301D87BB49}
4 | 18.4
5 | None
6 | TimerQueuesConsole.dpr
7 | True
8 | Debug
9 | Win64
10 | 130
11 | Console
12 |
13 |
14 | true
15 |
16 |
17 | true
18 | Base
19 | true
20 |
21 |
22 | true
23 | Base
24 | true
25 |
26 |
27 | true
28 | Base
29 | true
30 |
31 |
32 | true
33 | Base
34 | true
35 |
36 |
37 | true
38 | Base
39 | true
40 |
41 |
42 | true
43 | Base
44 | true
45 |
46 |
47 | true
48 | Base
49 | true
50 |
51 |
52 | true
53 | Base
54 | true
55 |
56 |
57 | true
58 | Base
59 | true
60 |
61 |
62 | true
63 | Cfg_1
64 | true
65 | true
66 |
67 |
68 | true
69 | Cfg_1
70 | true
71 | true
72 |
73 |
74 | true
75 | Base
76 | true
77 |
78 |
79 | .\$(Platform)\$(Config)
80 | .\Bin
81 | false
82 | false
83 | false
84 | false
85 | false
86 | RESTComponents;emsclientfiredac;DataSnapFireDAC;FireDACIBDriver;emsclient;FireDACCommon;RESTBackendComponents;soapserver;CloudService;FireDACCommonDriver;inet;FireDAC;FireDACSqliteDriver;soaprtl;soapmidas;$(DCC_UsePackage)
87 | System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)
88 | TimerQueuesConsole
89 | ZMQLOGGING;$(DCC_Define)
90 | ..\..\GrijjyFoundation;$(DCC_UnitSearchPath)
91 |
92 |
93 | DBXSqliteDriver;DBXInterBaseDriver;tethering;bindcompfmx;fmx;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;bindengine;DataSnapClient;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;DbxCommonDriver;xmlrtl;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)
94 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png
95 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png
96 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png
97 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png
98 | $(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png
99 | $(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png
100 | $(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png
101 | $(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png
102 | $(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png
103 | android-support-v4.dex.jar;cloud-messaging.dex.jar;fmx.dex.jar;google-analytics-v2.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar;google-play-services-ads-7.0.0.dex.jar;google-play-services-analytics-7.0.0.dex.jar;google-play-services-base-7.0.0.dex.jar;google-play-services-identity-7.0.0.dex.jar;google-play-services-maps-7.0.0.dex.jar;google-play-services-panorama-7.0.0.dex.jar;google-play-services-plus-7.0.0.dex.jar;google-play-services-wallet-7.0.0.dex.jar
104 |
105 |
106 | DBXSqliteDriver;fmxase;DBXInterBaseDriver;tethering;bindcompfmx;fmx;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;bindengine;DataSnapClient;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;DbxCommonDriver;xmlrtl;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)
107 |
108 |
109 | DBXSqliteDriver;fmxase;DBXInterBaseDriver;tethering;bindcompfmx;fmx;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;bindengine;DataSnapClient;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;DbxCommonDriver;xmlrtl;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)
110 |
111 |
112 | DBXSqliteDriver;fmxase;DBXInterBaseDriver;tethering;bindcompfmx;fmx;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;bindengine;DataSnapClient;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;DbxCommonDriver;xmlrtl;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)
113 |
114 |
115 | FireDACADSDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;inetdb;emsedge;dbexpress;IndyCore;dsnap;DataSnapCommon;DataSnapConnectors;bindengine;FireDACOracleDriver;FireDACMySQLDriver;FireDACCommonODBC;DataSnapClient;IndySystem;FireDACDb2Driver;FireDACInfxDriver;emshosting;FireDACPgDriver;FireDACASADriver;FireDACTDataDriver;DbxCommonDriver;DataSnapServer;xmlrtl;DataSnapNativeClient;rtl;DbxClientDriver;CustomIPTransport;bindcomp;dbxcds;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;dbrtl;IndyProtocols;FireDACMongoDBDriver;DataSnapServerMidas;$(DCC_UsePackage)
116 |
117 |
118 | DBXSqliteDriver;fmxase;DBXInterBaseDriver;tethering;FireDACMSSQLDriver;bindcompfmx;DBXOracleDriver;inetdb;emsedge;fmx;fmxdae;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;bindengine;DBXMySQLDriver;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;DataSnapClient;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;emshosting;FireDACPgDriver;FireDACASADriver;FireDACTDataDriver;DbxCommonDriver;DataSnapServer;xmlrtl;DataSnapNativeClient;fmxobj;FireDACDSDriver;rtl;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;bindcomp;DBXInformixDriver;IndyIPClient;dbxcds;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;DataSnapServerMidas;$(DCC_UsePackage)
119 | true
120 |
121 |
122 | DBXSqliteDriver;fmxase;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;tethering;svnui;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;svn;DBXOracleDriver;inetdb;emsedge;fmx;fmxdae;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;DataSnapCommon;DataSnapConnectors;VCLRESTComponents;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;Grijjy.Package.RTL;FireDACCommonODBC;DataSnapClient;IndyIPCommon;bindcompdbx;TMSListControlsDXE11;vcl;IndyIPServer;DBXSybaseASEDriver;IndySystem;FireDACDb2Driver;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;emshosting;FireDACPgDriver;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;DbxCommonDriver;DataSnapServer;xmlrtl;DataSnapNativeClient;fmxobj;vclwinx;FireDACDSDriver;rtl;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;Grijjy.Package.FMX;DataSnapServerMidas;$(DCC_UsePackage)
123 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
124 | Debug
125 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=
126 | 1033
127 | true
128 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png
129 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png
130 |
131 |
132 | DBXSqliteDriver;fmxase;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;tethering;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;DBXOracleDriver;inetdb;emsedge;fmx;fmxdae;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;DataSnapCommon;DataSnapConnectors;VCLRESTComponents;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;DataSnapClient;IndyIPCommon;bindcompdbx;vcl;IndyIPServer;DBXSybaseASEDriver;IndySystem;FireDACDb2Driver;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;emshosting;FireDACPgDriver;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;DbxCommonDriver;DataSnapServer;xmlrtl;DataSnapNativeClient;fmxobj;vclwinx;FireDACDSDriver;rtl;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;DataSnapServerMidas;$(DCC_UsePackage)
133 | true
134 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png
135 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png
136 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)
137 | Debug
138 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=
139 | 1033
140 |
141 |
142 | DEBUG;$(DCC_Define)
143 | true
144 | false
145 | true
146 | true
147 | true
148 |
149 |
150 | false
151 |
152 |
153 | 1033
154 | (None)
155 |
156 |
157 | false
158 | RELEASE;$(DCC_Define)
159 | 0
160 | 0
161 |
162 |
163 |
164 | MainSource
165 |
166 |
167 | Cfg_2
168 | Base
169 |
170 |
171 | Base
172 |
173 |
174 | Cfg_1
175 | Base
176 |
177 |
178 |
179 | Delphi.Personality.12
180 | Application
181 |
182 |
183 |
184 | TimerQueuesConsole.dpr
185 |
186 |
187 | Microsoft Office 2000 Sample Automation Server Wrapper Components
188 | Microsoft Office XP Sample Automation Server Wrapper Components
189 |
190 |
191 |
192 |
193 |
194 | true
195 |
196 |
197 |
198 |
199 | TimerQueuesConsole.exe
200 | true
201 |
202 |
203 |
204 |
205 | libzmq-linux64.so
206 | true
207 |
208 |
209 |
210 |
211 | libzmq-linux64.so
212 | true
213 |
214 |
215 |
216 |
217 | true
218 |
219 |
220 |
221 |
222 | true
223 |
224 |
225 |
226 |
227 | true
228 |
229 |
230 |
231 |
232 | TimerQueuesConsole
233 | true
234 |
235 |
236 |
237 |
238 | 1
239 |
240 |
241 | Contents\MacOS
242 | 1
243 |
244 |
245 | Contents\MacOS
246 | 0
247 |
248 |
249 |
250 |
251 | classes
252 | 1
253 |
254 |
255 |
256 |
257 | library\lib\armeabi-v7a
258 | 1
259 |
260 |
261 |
262 |
263 | library\lib\armeabi
264 | 1
265 |
266 |
267 |
268 |
269 | library\lib\mips
270 | 1
271 |
272 |
273 |
274 |
275 | library\lib\armeabi-v7a
276 | 1
277 |
278 |
279 |
280 |
281 | res\drawable
282 | 1
283 |
284 |
285 |
286 |
287 | res\values
288 | 1
289 |
290 |
291 |
292 |
293 | res\drawable
294 | 1
295 |
296 |
297 |
298 |
299 | res\drawable-xxhdpi
300 | 1
301 |
302 |
303 |
304 |
305 | res\drawable-ldpi
306 | 1
307 |
308 |
309 |
310 |
311 | res\drawable-mdpi
312 | 1
313 |
314 |
315 |
316 |
317 | res\drawable-hdpi
318 | 1
319 |
320 |
321 |
322 |
323 | res\drawable-xhdpi
324 | 1
325 |
326 |
327 |
328 |
329 | res\drawable-small
330 | 1
331 |
332 |
333 |
334 |
335 | res\drawable-normal
336 | 1
337 |
338 |
339 |
340 |
341 | res\drawable-large
342 | 1
343 |
344 |
345 |
346 |
347 | res\drawable-xlarge
348 | 1
349 |
350 |
351 |
352 |
353 | 1
354 |
355 |
356 | Contents\MacOS
357 | 1
358 |
359 |
360 | 0
361 |
362 |
363 |
364 |
365 | Contents\MacOS
366 | 1
367 | .framework
368 |
369 |
370 | 0
371 |
372 |
373 |
374 |
375 | 1
376 | .dylib
377 |
378 |
379 | 1
380 | .dylib
381 |
382 |
383 | 1
384 | .dylib
385 |
386 |
387 | Contents\MacOS
388 | 1
389 | .dylib
390 |
391 |
392 | 0
393 | .dll;.bpl
394 |
395 |
396 |
397 |
398 | 1
399 | .dylib
400 |
401 |
402 | 1
403 | .dylib
404 |
405 |
406 | 1
407 | .dylib
408 |
409 |
410 | Contents\MacOS
411 | 1
412 | .dylib
413 |
414 |
415 | 0
416 | .bpl
417 |
418 |
419 |
420 |
421 | 0
422 |
423 |
424 | 0
425 |
426 |
427 | 0
428 |
429 |
430 | 0
431 |
432 |
433 | Contents\Resources\StartUp\
434 | 0
435 |
436 |
437 | 0
438 |
439 |
440 |
441 |
442 | 1
443 |
444 |
445 | 1
446 |
447 |
448 | 1
449 |
450 |
451 |
452 |
453 | 1
454 |
455 |
456 | 1
457 |
458 |
459 | 1
460 |
461 |
462 |
463 |
464 | 1
465 |
466 |
467 | 1
468 |
469 |
470 | 1
471 |
472 |
473 |
474 |
475 | 1
476 |
477 |
478 | 1
479 |
480 |
481 | 1
482 |
483 |
484 |
485 |
486 | 1
487 |
488 |
489 | 1
490 |
491 |
492 | 1
493 |
494 |
495 |
496 |
497 | 1
498 |
499 |
500 | 1
501 |
502 |
503 | 1
504 |
505 |
506 |
507 |
508 | 1
509 |
510 |
511 | 1
512 |
513 |
514 | 1
515 |
516 |
517 |
518 |
519 | 1
520 |
521 |
522 |
523 |
524 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
525 | 1
526 |
527 |
528 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
529 | 1
530 |
531 |
532 |
533 |
534 | 1
535 |
536 |
537 | 1
538 |
539 |
540 |
541 |
542 | ..\
543 | 1
544 |
545 |
546 | ..\
547 | 1
548 |
549 |
550 |
551 |
552 | 1
553 |
554 |
555 | 1
556 |
557 |
558 | 1
559 |
560 |
561 |
562 |
563 | 1
564 |
565 |
566 | 1
567 |
568 |
569 | 1
570 |
571 |
572 |
573 |
574 | ..\
575 | 1
576 |
577 |
578 |
579 |
580 | Contents
581 | 1
582 |
583 |
584 |
585 |
586 | Contents\Resources
587 | 1
588 |
589 |
590 |
591 |
592 | library\lib\armeabi-v7a
593 | 1
594 |
595 |
596 | 1
597 |
598 |
599 | 1
600 |
601 |
602 | 1
603 |
604 |
605 | 1
606 |
607 |
608 | Contents\MacOS
609 | 1
610 |
611 |
612 | 0
613 |
614 |
615 |
616 |
617 | 1
618 |
619 |
620 | 1
621 |
622 |
623 |
624 |
625 | Assets
626 | 1
627 |
628 |
629 | Assets
630 | 1
631 |
632 |
633 |
634 |
635 | Assets
636 | 1
637 |
638 |
639 | Assets
640 | 1
641 |
642 |
643 |
644 |
645 |
646 |
647 |
648 |
649 |
650 |
651 |
652 |
653 | False
654 | False
655 | False
656 | False
657 | True
658 | False
659 | False
660 | True
661 |
662 |
663 | 12
664 |
665 |
666 |
667 |
668 |
669 |
--------------------------------------------------------------------------------
/Example/TimerQueuesConsole.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grijjy/DelphiPlatformTimerQueue/6a45dcafa79dffaa6a17c671e6ede385fce51deb/Example/TimerQueuesConsole.res
--------------------------------------------------------------------------------
/Example/info.plist.TemplateOSX.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%VersionInfoPListKeys%>
6 | <%ExtraInfoPListKeys%>
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Example/info.plist.TemplateiOS.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%VersionInfoPListKeys%>
6 | <%ExtraInfoPListKeys%>
7 |
8 |
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Using the Apple's Grand Central Dispatch and Android's ScheduledThreadPoolExecutor for Delphi timers
2 | You are probably already familiar with the NSTimer on iOS/macOS and JTimer on Android for timer events. In addition to the basic timers, most operating systems offer a more advanced threaded schedule event API. On Android there is the [ScheduledThreadPoolExecutor](https://developer.android.com/reference/java/util/concurrent/ScheduledThreadPoolExecutor) which allows you to launch a Runnable at a specific time period. On iOS/macOS the operating system includes the [Grand Central Dispatch](https://developer.apple.com/documentation/DISPATCH) (GCD) which allows you to schedule events. On Windows we have the CreateTimerQueueTimer APIs for a similar purpose.
3 |
4 | In this article we will show how you can use these APIs on mobile, desktop and server platforms in Delphi in a unified manner and receive OnTimer() events that you are already familiar with.
5 |
6 | Of course, it is possible to create your own thread pool and simulate timer events. However, the operating system already has it's own kernel-managed thread pool for scheduled events. By leveraging these APIs you can share thread resources across all the processes on the device and this is especially important for platforms where it is not advisable to create numerous threads. Unlike a regular timer object, you can run more than one scheduled timer from the same timer object, thereby avoiding allocating numerous individual timer objects. Timer events can share threads from the OS pool if the event durations don't exceed the interval rate and more.
7 |
8 | Also, there are situations where you need a scheduled timer but you don't have a main application loop to fire events or a window, such as library modules, server logic, etc. You can go through the effort of creating hidden windows of course, but the OS based scheduled event APIs don't have this limitation.
9 |
10 | - On Android we use the JScheduledThreadPoolExecutor class and JRunnable to allow the OS to manage the thread pool
11 | - On macOS/iOS we use the Grand Central Dispatch and allow the OS the OS to manage the thread pool
12 | - On Windows we use the CreateTimerQueueTimer() API to allow the OS/kernel to manage the thread pool and callback.
13 | - On Linux64 we use Epoll and the TimerFd capability to signal timer events along with our own managed thread pool
14 |
15 | For more information about us, our support and services visit the [Grijjy homepage](http://www.grijjy.com) or the [Grijjy developers blog](http://blog.grijjy.com).
16 |
17 | The example contained here depends upon part of our [Grijjy Foundation library](https://github.com/grijjy/GrijjyFoundation).
18 |
19 | The source code and related example repository is hosted on GitHub at [https://github.com/grijjy/DelphiPlatformTimerQueue](https://github.com/grijjy/DelphiPlatformTimerQueue).
20 |
21 | ## Grand Central Dispatch on iOS and macOS
22 | On iOS and macOS we have a unified approach called the [Grand Central Dispatch](https://developer.apple.com/documentation/DISPATCH). The GCD provides numerous capabilities to help developers with parallel applications on Apple devices. Apple recommends this approach for threading events so that all applications on a given device can better share system resources.
23 |
24 | To create a event that repeats at a specified interval, you need to use 5 core APIs of the GCD:
25 | 1. Use the `dispatch_get_global_queue()` API to create a global queue that you will share with all your timers.
26 | 2. Call `dispatch_source_create()` to create a timer that is associated with the queue.
27 | 3. Call `dispatch_source_set_timer()` to specify the interval and accuracy of your timer.
28 | 4. Call `dispatch_source_set_event_handler()` to specify the callback for the event.
29 | 5. Finally call `dispatch_resume()` to start your timer.
30 |
31 | The APIs are straightforward to use, except for a couple of things. First, Delphi is currently missing some of these constants and exports, so we include a conversion called Macapi.Gcd.pas in our Grijjy Repository.
32 |
33 | Secondly, and far more difficult is the usage of the `dispatch_source_set_event_handler()` API which uses an ObjectiveC block for the callback. There are numerous approaches to using ObjC blocks in Delphi code, but we prefer a method implemented by the team over at Tamosoft. We include a unit to simplify those ObjC blocks in Delphi based upon their [blog article](https://habr.com/post/325204/). Their methodology makes the usage of an ObjC block in Delphi as simple as the following example,
34 |
35 | ```Delphi
36 | TObjCBlock.CreateBlockWithProcedure(
37 | procedure(p1: NSInteger; p2: Pointer)
38 | begin
39 | if Assigned(FOnTimer) then
40 | FOnTimer(Self);
41 | end));
42 | ```
43 | Here our anonymous method runs when the block is called which in turn calls our timer event.
44 |
45 | We only need to create a single global queue for all the GCD timers, so in Delphi we could use a simple method to check for the existance of the global queue, and create one if required. For example,
46 | ```Delphi
47 | function GetGlobalQueue: dispatch_queue_t;
48 | begin
49 | if FGlobalQueue = nil then
50 | FGlobalQueue := dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
51 | Result := FGlobalQueue;
52 | end;
53 | ```
54 |
55 | Then to finally put it all together we create our timer using `DISPATCH_SOURCE_TYPE_TIMER` and use the `dispatch_source_set_timer` API to specify both the startup delay and the interval. We could choose to have the timer fire immediately upon startup, but it is customary to have the first event after the first interval, so we provide a delay which matches the interval. If you are concerned with accuracy of the timer, the GCD API also provides an accuracy leeway.
56 |
57 | Then we call `dispatch_source_set_event_handler` with our OnTimer() event as an ObjC block followed by `dispatch_resume` to start the timer.
58 |
59 | ```Delphi
60 | FDispatchTimer := dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, FTimerQueue.GlobalQueue);
61 | if Assigned(FDispatchTimer) then
62 | begin
63 | dispatch_source_set_timer(FDispatchTimer,
64 | dispatch_time(DISPATCH_TIME_NOW, AInterval * NSEC_PER_MSEC), // Start delay
65 | AInterval * NSEC_PER_MSEC, // Interval
66 | 0); // Leeway
67 |
68 | dispatch_source_set_event_handler(FDispatchTimer,
69 | TObjCBlock.CreateBlockWithProcedure(
70 | procedure(p1: NSInteger; p2: Pointer)
71 | begin
72 | if Assigned(FOnTimer) then
73 | FOnTimer(Self);
74 | end));
75 |
76 | dispatch_resume(FDispatchTimer);
77 | ```
78 |
79 | To change the interval rate of the timer, while the timer is operating the GCD you simply call the `dispatch_source_set_timer` method again:
80 |
81 | ```Delphi
82 | dispatch_source_set_timer(FDispatchTimer,
83 | dispatch_time(DISPATCH_TIME_NOW, AInterval * NSEC_PER_MSEC), AInterval * NSEC_PER_MSEC, 0);
84 | ```
85 |
86 | ## ScheduledThreadPoolExecutor for Android
87 | On Android we have a class called the ScheduledThreadPoolExecutor that allows us to create timers using an API called `scheduleAtFixedRate`.
88 |
89 | To create a ScheduledThreadPoolExecutor we simple define one and initialize it. During the initialization we must specify the total maximum threads in the pool.
90 |
91 | ```Delphi
92 | var
93 | ScheduledThreadPoolExecutor: JScheduledThreadPoolExecutor;
94 |
95 | ScheduledThreadPoolExecutor := _TJScheduledThreadPoolExecutor.JavaClass.init(ANDROID_THREAD_POOL_SIZE);
96 |
97 | ```
98 | The ScheduledThreadPoolExecutor expects to call a Runnable object, so to use this API we must first create a Runnable object. The following example shows a simple example of how this is done:
99 | ```Delphi
100 | var
101 | FRunnable: JRunnable;
102 |
103 | type
104 | TAndroidRunnable = class(TJavaLocal, JRunnable)
105 | private
106 | FTimer: TgoTimer;
107 | public
108 | constructor Create(const ATimer: TgoTimer);
109 | procedure run; cdecl;
110 | end;
111 |
112 | FRunnable := TAndroidRunnable.Create(Self);
113 | ```
114 | Then to startup your timer you only need to call the `scheduleAtFixedRate` API.
115 |
116 | ```Delphi
117 | FScheduledFuture := ScheduledThreadPoolExecutor.scheduleAtFixedRate(FRunnable, AInterval, AInterval, TJTimeUnit.JavaClass.MILLISECONDS);
118 | ```
119 | A few things to note here. First off, just like the Apple GCD, you are passing both an initial delay and an interval so the timer events start at the first interval. More importantly we are returning a ScheduledFuture object here. The ScheduledFuture allows you to interact with your timer. Delphi's import for the `scheduleAtFixedRate` API does not return a ScheduledFuture, so in our implementation we created another version of the import.
120 |
121 | To change the interval rate of a running timer you only need to cancel the existing timer, and call `scheduleAtFixedRate` again, for example:
122 |
123 | ```Delphi
124 | FScheduledFuture.cancel(True);
125 | FScheduledFuture := ScheduledThreadPoolExecutor.scheduleAtFixedRate(FRunnable, AInterval, AInterval, TJTimeUnit.JavaClass.MILLISECONDS);
126 | ```
127 | ## Windows CreateTimerQueueTimer and Linux EPoll
128 | On Windows we have an API called `CreateTimerQueueTimer` to perform a substantially similar thread based timer. On Linux we have a concept of timer file descriptors which we can use with the Epoll APIs and our own thread pool to time events.
129 |
130 | Since we covered these concepts in detail for Windows and Linux timers in a [recent article](https://blog.grijjy.com/2017/04/20/cross-platform-timer-queues-for-windows-and-linux/), I won't go into detail in this article. Please refer to that article if your interest is primarily Windows or Linux.
131 |
132 | However, we have merged those concepts into a single unit and a unified class so that the TgoTimer() related unit and classes work the same on all platforms including iOS, macOS, Android, Windows and Linux. As a developer you can simply use the class and setup your OnTimer() events and the interface is identical.
133 |
134 | ## Considerations
135 | Please keep in mind that there are some differences between platforms in how they handle overlapped timer events (when your total callback time exceeds the interval rate). Some of the platform specific APIs will simply issue a new thread and timer event at the interval rate while others will wait until you return.
136 |
137 | If you don't want overlapping events, then one way to handle this is to check in your own OnTimer() event if you are already executing and exit. You could use an Atomic operation to check or a TryLock condition.
138 |
139 | Of course you may want your timer events to overlap, especially if your timer event is time sensitive. As a developer you have to consider your scenario.
140 |
141 | Also Delphi native timers are designed to be synchronized with the main application thread. This allows you to update the user interface from your timer event. Your normal Delphi timer will be blocked in cases that the operation takes longer than the interval and this is sometimes desired behavior.
142 |
143 | If you want to synchronize the TgoTimer event with the application thread, you could simply call TThread.Synchronize in your OnTimer() event,
144 |
145 | ```Delphi
146 | TThread.Synchronize(nil,
147 | procedure
148 | begin
149 | // Update the user interface
150 | end);
151 | ```
152 | We do this in our Firemonkey example so that we can update a Memo component from our OnTimer() event.
153 |
154 | ## Examples and source code
155 | In our GitHub repository we have included both a cross-platform Firemonkey based example that runs on all platforms to demonstrate timer basics and a console application for Windows and Linux.
156 |
157 | The example program at [https://github.com/grijjy/DelphiPlatformTimerQueue](https://github.com/grijjy/DelphiPlatformTimerQueue).
158 |
159 | ## Conclusion
160 | In the end it's not a lot of code to unify timers on all platforms, but it took us a while to figure out these nuances on mobile platforms. We hope you find this article helpful for your efforts and a useful addition to your application. We have utilized threaded timers for silent reconnection logic, heartbeat logic on servers and more.
161 |
162 | For more information about us, our support and services visit the [Grijjy homepage](http://www.grijjy.com) or the [Grijjy developers blog](http://blog.grijjy.com).
163 |
164 | The base classes described herein are part of our [Grijjy Foundation library](https://github.com/grijjy/GrijjyFoundation).
--------------------------------------------------------------------------------