2016-02-17 3 views
1

Использование Delphi 10 Seattle Обновление 1 для создания приложения для Android.Delphi 10 Seattle Справочная служба и темы

Основная цель состоит в том, чтобы приложить всплывающее уведомление каждые несколько (4) часов, чтобы напомнить пользователю встать и переместиться.

Я создал базовый интерфейс и создал фоновое обслуживание. В сервисе я могу использовать TNotificationCenter, чтобы опубликовать уведомление просто отлично, но мне нужно публиковать уведомление с регулярным интервалом.

На основе предложений, найденных на следующих сайтах ...

Я понял, что не могу использовать TTimer и Android-сервис , Я также попытался создать TTask, TThread.CreateAnonymousThread и старомодный потомок TThread как из AndroidServiceStartCommand, так и из события AndroidServiceCreate.

Все они выдают ту же ошибку после завершения команды сна. «Проект MoveProof.apk поднял исключение неисправности класса сегмента (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

Для этого вам не нужна услуга. Просто используйте [AlarrmManager] (http://developer.android.com/reference/android/app/AlarmManager.html). В личном примечании * почему * вы беспокоитесь о создании новых приложений в Delphi? AndroidStudio бесплатно, полностью поддерживается и легко найти помощь. Для кросс-платформенной разработки доступны гораздо лучшие инструменты. FWIW, я разработал в Delphi с первой версии (1995). Это просто неправильный инструмент для мобильных устройств. – 323go

+0

Segfault (11) - это эквивалент нарушения прав доступа в Windows. Вы получаете недопустимую память. Почему вы вызываете 'JavaService.stopSelf()'? И почему вы запускаете цикл while в процедуре 'Synchronize()'? Ed? –

+0

@ 323go - AlarmManager выглядит так, как будто это путь. Я разрабатываю настольные приложения OSX/Win, поэтому у меня уже есть Delphi, и я только начинаю изучать мобильные устройства, поэтому сейчас я придерживаюсь «дома». –

ответ

-1

Вам не нужна услуга для этого, как предлагалось 323go.

сервис должен использоваться только тогда, когда он определенно необходим, потому что он потребляет системные ресурсы и истощает срок службы батареи, поэтому используйте их на основе необходимости.

Вы можете использовать родной AlarmManager.setRepeating метод, который будет создавать нативный уведомления повторяющееся в пользовательском интервале заданного вами, решение, однако, является Android конкретных

относятся к моему ответу здесь Custom notification interval

Сразу отметим, что для ваш случай, MyNotification.RepeatIntervalinMills интервал в миллисекундах, что вы хотите, чтобы ваши уведомления стрелять в это в вашем случае 4 часа было бы

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

Просто настройка пользовательского интервала на самом деле не работает для меня, потому что каждый раз мне нужно другое сообщение, а также событие, в которое нужно выполнить другую работу. AlarmManager действительно выглядит так, как хотелось бы, но я пока не могу описать все примеры Delphi. –

0

Вам не нужно помещать DoNotification в поток. Просто настройте TTask с вечным циклом в вашем AndroidServiceCreate, а затем проверьте прошедшее время, и когда он будет передан, тогда вызовите 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; 

Хорошее эмпирическое правило для Android услуг в Delphi, чтобы написать простейший код, который вы можете сделать, чтобы получить работу и не более.

Смежные вопросы