Delphi 10西雅图后台服务和主题

时间:2016-02-17 04:19:14

标签: android multithreading delphi service firemonkey

使用Delphi 10 Seattle Update 1创建Android应用程序。

基本目标是让应用程序每隔几(4)小时弹出一个通知,提醒用户起床和移动。

我创建了基本UI并创建了后台服务。在服务中,我可以使用TNotificationCenter发布通知,但我需要定期发布通知。

根据以下网站的建议......

我意识到我无法使用TTimer和Android服务。我还试图从AndroidServiceStartCommand和AndroidServiceCreate事件创建一个TTask,TThread.CreateAnonymousThread和一个老式的TThread后代。

所有这些都在sleep命令完成后抛出相同的错误。 “Project MoveProof.apk引发了异常类Segment fault(11)”

以下是我现在使用的代码....

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.

我对线程没有经验,所以也许我在做同步时出错了。任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:0)

没有必要将DoNotification放入线程中。只需在AndroidServiceCreate中设置一个带有永久循环的TTask,然后检查已用时间,当它通过时,再调用DoNotification。

  T := TTask.Run (procedure
  begin
    TimeNow := Now;
    Count := 0;
    while true do
    begin
      sleep(20000);
      if SecondsBetween(TimeNow, Now) >= Floor(4 * 60 * 60) then
      begin
        DoNotification;
        TimeNow := Now;
      end;
    end;
  end);

您的通知看起来比它需要的更复杂,并且您在那里使用的不必要的循环可能是您的分段错误的原因。

  myNotification := NotificationCenter1.CreateNotification;
  try
    MyNotification.Name := 'ServiceNotification';
    MyNotification.Title := 'Android Service Notification';
    MyNotification.AlertBody := 'hello host, I'm your service'
    MyNotification.FireDate := Now;
    NotificationCenter1.PresentNotification(MyNotification); 
  finally
    myNotification.DisposeOf;
  end;

Delphi中Android服务的经验法则是编写最简单的代码来完成工作,而不是更多。

答案 1 :(得分:-1)

如323go建议的那样,您不需要服务来执行此操作。

服务只应在明确需要时使用,因为它会消耗系统资源并耗尽电池寿命,因此只需要使用它们。

您可以使用本地AlarmManager.setRepeating方法,该方法将在您指定的自定义时间间隔内创建本机定期通知,但解决方案是Android特定的

请参阅我的回答Custom notification interval

请注意,对于您的情况,MyNotification.RepeatIntervalinMills毫秒的间隔,您希望触发通知,因此在4小时的情况下,它将是

MyNotification.RepeatIntervalinMills := 14400000 // That is 4 hours in Milliseconds