如何防止FireMonkey应用程序/服务在后台停止运行?

时间:2018-09-25 18:41:10

标签: android delphi android-service firemonkey

我正在尝试编写FireMonkey应用程序,即使该设备的用户切换到另一个应用程序或显示器关闭,该应用程序也必须在后台执行一些工作(不是很繁重的任务)。在此任务中,我定期将HTTP请求(带有TIdHTTP)发送到服务器,以获取一小部分数据并测试应用程序是否仍在运行。

默认情况下,Android在后台或当用户关闭显示器时关闭应用程序。我尝试了两种方法来保持我的应用运行:

  1. 通过Android的用户界面将应用添加到“受保护的应用”列表中(禁用应用的电源优化功能/“在屏幕关闭时继续运行”)。

  2. 我通过项目向导使用粘性标记(START_STICKY)创建了本地服务(TAndroidService),并将任务代码移到了那里。

从主机应用程序启动服务:

// LIntent and LServiceName are stored in TForm1
procedure TForm1.StartMyService();
begin
  LIntent := TJIntent.Create();
  LServiceName := 'com.embarcadero.services.MyService';
  LIntent.setClassName(TAndroidHelper.Context.getPackageName(), TAndroidHelper.StringToJString(LServiceName));
  TAndroidHelper.Activity.startService(LIntent);
end;

服务中的OnStartCommand事件如下:

function TMyServiceDM.AndroidServiceStartCommand(const Sender: TObject;
  const Intent: JIntent; Flags, StartId: Integer): Integer;
begin
  Result := TJService.JavaClass.START_STICKY;

  LThread := TThread.CreateAnonymousThread(procedure
    begin

      while True do
      begin
        // ... Task performed here periodically and exits loop when needed ...

        // Sleep for 1 minute
        LThread.Sleep(60000);
      end;

      // Before thread stops, also stop the Java service
      JavaService.stopSelf(StartId);
    end);

  LThread.FreeOnTerminate := False;
  LThread.Start();
end;

仅当通过电源电缆线(例如,通过本机的USB电缆)连接设备时,该应用程序仍在后台运行,即使显示屏已关闭 BUT 。如果拔下电源线,则即使屏幕停留在前台,该应用似乎也会在屏幕关闭时立即停止。

我做错什么了吗?如何使我的服务在后台运行(例如执行类似操作的Messenger应用)?我知道,Android 6.0(API级别23)及更高版本使用一种称为“ Doze”的功能,而Google希望其开发人员使用FCM(Firebase Cloud Messaging)。我只是最近才读到它,希望至少禁用该应用程序的电源优化功能可以解决此问题,但不能。

1 个答案:

答案 0 :(得分:0)

例如,使用android pre-oreo,您可以执行以下操作:

AndroidManifest.xml

  <receiver android:name="com.myapp.StartServiceBroadcastReceiver">  
    <intent-filter>  
      <action android:name="android.intent.action.BOOT_COMPLETED" />  
    </intent-filter>  
  </receiver> 

在StartServiceBroadcastReceiver中,我要做的事情:

  @Override
  public void onReceive(Context context, Intent intent) {

    try {

        /* start the location service */  
        Intent startServiceIntent = new Intent(context, LocationService.class);
        context.startService(startServiceIntent);

    } catch (Throwable e){ Log.e(TAG, "Exception", e); }  

  }

,但是在android oreo +上不再有效!现在开始服务返回

  

不允许启动服务意图

您需要调用startForegroundService来代替,但这对于向最终用户显示通知图标有很大的缺点:(