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.
There's no need to put your DoNotification in a thread. Just setup a TTask with an eternal loop in your AndroidServiceCreate, and then check the elapsed time, and when it's passed, call the DoNotification then.
Your notification looks more complicated than it needs to be, and the unnecessary loop you used there might be the cause of your segmentation fault.
The good rule of thumb for Android services in Delphi is to write the simplest code you can to get the job done and no more.
You don't need a service to do this, as 323go suggested.
a service should only be used when it is definitely needed because it consumes system resources and drains battery life, so use them on a need to only basis.
You can use the native
AlarmManager.setRepeating
method that will create a native recurring notification in a custom interval specified by you, the solution however is Android specificrefer to my answer here Custom notification interval
Just note that for your case that
MyNotification.RepeatIntervalinMills
is the interval in Milliseconds that you want your notifications to fire in so in your case of 4 Hours it would be