Delphi 10 Seattle Background Service and Threads

  

Using Delphi 10 Seattle Update 1 to create an Android application.

Basic goal is to have an application the pops up a notification every few (4) hours to remind the user to get up and move.

I have created the basic UI and created the background service. In the service I can use a TNotificationCenter to post a notification just fine, but I need to post a notification at a regular interval.

Based on suggestions found at the following sites…

http://blog.blong.com/2015/02/delphi-and-android-services-part-3.html
http://blog.marcocantu.com/blog/2014_may_background_delphi_android_threads.html
embarcadero delphi XE10 android service with a timer
Also the AndroidNotificationServiceDemo that ships with the product…

I realized that I cannot use a TTimer in and Android Service. I have also tried to create a TTask, TThread.CreateAnonymousThread, and an old fashioned TThread descendant from both the AndroidServiceStartCommand and the AndroidServiceCreate event.

All of them throw the same error after the sleep command finishes. “Project MoveProof.apk raised exception class Segment fault (11)”

Here is the code I am using now….

unit UnitServiceMain;

interface

uses
System.SysUtils
, System.Classes
, System.Android.Service
, System.Notification

, AndroidApi.JNI.GraphicsContentViewText
, Androidapi.JNI.Os

;

type
TServiceThread = class;

TNotes = Array of String;

TAndroidServiceDM = class(TAndroidService)
NotificationCenterNotes: TNotificationCenter;
function AndroidServiceStartCommand(const Sender: TObject; const Intent: JIntent; Flags, StartId: Integer): Integer;
procedure AndroidServiceCreate(Sender: TObject);
procedure AndroidServiceDestroy(Sender: TObject);
private
FNotes: TArray<string>;
FThread: TServiceThread;
public
var Running: Boolean;

Procedure LoadArray;
Property Notes:TArray<string> read FNotes;
end;

TServiceThread = class(TThread)
public
Procedure Execute; override;
Procedure DoNotification;
end;

var
AndroidServiceDM: TAndroidServiceDM;

implementation

{%CLASSGROUP ‘FMX.Controls.TControl’}

{$R *.dfm}

Uses
System.Threading
, Androidapi.JNI.App
;

{ TServiceThread }

procedure TServiceThread.DoNotification;
Var
NoteId: Integer;
MyNotification: TNotification;
begin
while (AndroidServiceDM <> nil) and AndroidServiceDM.Running do
Begin
try
if (AndroidServiceDM <> nil) and AndroidServiceDM.Running then
Begin
AndroidServiceDM.NotificationCenterNotes.CancelAll;
NoteID := Random(High(AndroidServiceDM.Notes));
MyNotification := AndroidServiceDM.NotificationCenterNotes.CreateNotification;
try
MyNotification.Name := ‘LoveNoteMessage’+InttoStr(NoteID);
MyNotification.EnableSound := False;
MyNotification.Number := NoteID;
MyNotification.Title := ‘Michael Said…’;
MyNotification.AlertBody := AndroidServiceDM.Notes[NoteID];
AndroidServiceDM.NotificationCenterNotes.PresentNotification(MyNotification);
finally
MyNotification.DisposeOf;
end;
End;
except
on Exception do
// Need to log this…
end;
end;
end;

procedure TServiceThread.Execute;
begin
inherited;
Sleep( 20000 );
Synchronize(DoNotification);
end;

procedure TAndroidServiceDM.LoadArray;
begin
if Length(FNotes) = 0 then
Begin
FNotes := TArray<string>.Create
(
‘Get up and move.’,
‘Time to keep moving.’,
‘Lets take a walk.’,
‘Move.’
);
End;
end;

procedure TAndroidServiceDM.AndroidServiceCreate(Sender: TObject);
begin
Randomize;
LoadArray;
end;

procedure TAndroidServiceDM.AndroidServiceDestroy(Sender: TObject);
begin
FThread.Terminate;
FThread := Nil;
end;

function TAndroidServiceDM.AndroidServiceStartCommand(const Sender: TObject; const Intent: JIntent; Flags, StartId: Integer): Integer;
begin
JavaService.stopSelf;
Result := TJService.JavaClass.START_STICKY;
if not Running then
begin
Running := True;
FThread := TServiceThread.Create(False);
end;
end;

end.

I am not that experienced with threads, so maybe I am doing something wrong with synchronization. Any help would be appreciated.

Comments are closed.