You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi 12开发Android后台Service关闭问题求助:主应用关闭后服务停止

Delphi 12 Android后台Service保活与TCP消息处理方案

一、启动标志的调整

你当前使用的START_STICKY是基础保活选项,但针对TCP长连接场景,更推荐使用START_REDELIVER_INTENT——它会在Service被系统回收后,重新传递最后一次触发的Intent,更适合需要恢复网络连接的场景。不过这只是基础配置,核心还要解决Android系统对后台Service的限制问题。

二、让Service持续运行的核心措施(Android 8.0+必做)

从Android 8.0开始,系统对后台Service的管控极严,普通后台Service在主进程关闭后很快会被回收,必须将Service转为前台Service,通过显示持续通知告知系统该Service是用户主动需要的:

1. 修改Service的StartCommand代码

在TDM.AndroidServiceStartCommand中添加前台Service启动逻辑,同时启动TCP连接线程(避免阻塞主线程):

function TDM.AndroidServiceStartCommand(const Sender: TObject;
  const Intent: JIntent; Flags, StartId: Integer): Integer;
var
  NotificationBuilder: JNotificationBuilder;
  NotificationChannel: JNotificationChannel;
  NotificationManager: JNotificationManager;
  Notification: JNotification;
  ChannelID: JString;
begin
  // Android 8.0+必须创建通知渠道
  ChannelID := StringToJString('MyService_Channel');
  NotificationManager := TJNotificationManager.Wrap(
    TAndroidHelper.Context.getSystemService(TJContext.JavaClass.NOTIFICATION_SERVICE));
  if TAndroidHelper.SdkVersion >= 26 then
  begin
    NotificationChannel := TJNotificationChannel.JavaClass.init(ChannelID,
      StringToJString('后台消息服务'), TJNotificationManager.JavaClass.IMPORTANCE_LOW);
    NotificationManager.createNotificationChannel(NotificationChannel);
  end;

  // 构建前台通知
  NotificationBuilder := TJNotificationBuilder.JavaClass.init(TAndroidHelper.Context, ChannelID);
  NotificationBuilder.setContentTitle(StringToJString('消息服务运行中'))
    .setContentText(StringToJString('正在监听服务器消息'))
    .setSmallIcon(TAndroidHelper.Context.getApplicationInfo.icon);
  Notification := NotificationBuilder.build;

  // 启动为前台Service
  StartForeground(1, Notification);

  // 启动TCP连接线程(替换为你的实际TCP逻辑)
  TThread.CreateAnonymousThread(procedure
  begin
    // 在这里实现TCP套接字连接、消息接收逻辑
    // 注意:线程内要捕获异常,避免崩溃导致Service退出
  end).Start;

  // 选择START_REDELIVER_INTENT,适配长连接恢复场景
  Result := TJService.JavaClass.START_REDELIVER_INTENT;
end;

2. 更新AndroidManifest配置

添加前台Service权限,确保Service配置正确:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK" /> <!-- 可选,防止设备休眠断开TCP连接 -->

<service android:enabled="true" android:exported="false" android:label="MyService"
  android:process=":remote" android:name="com.embarcadero.services.MyService">
</service>

三、Service销毁后自动重启

即使是前台Service,极端场景下仍可能被系统回收,需要在OnDestroy事件中添加重启逻辑:

procedure TDM.AndroidServiceDestroy(Sender: TObject);
var
  RestartIntent: JIntent;
begin
  // 先关闭TCP连接、释放所有资源
  // ... 此处编写你的TCP连接关闭、线程释放逻辑 ...

  // 发送重启Intent,延迟1秒重启(避免频繁重启被系统限制)
  RestartIntent := TJIntent.Create;
  RestartIntent.setClassName(TAndroidHelper.Context, StringToJString('com.embarcadero.services.MyService'));
  TAndroidHelper.Context.startService(RestartIntent);
end;

注意:Android 12+对后台启动Service有更严格限制,若上述重启方式失效,可结合AlarmManager定时触发重启,或使用WorkManager作为兜底方案。

四、Destroy事件的正确处理

  • 在OnDestroy中必须优先关闭TCP套接字、释放所有占用资源(如线程、网络连接),避免内存泄漏。
  • 不要在OnDestroy中执行耗时操作,系统会快速回收Service进程,耗时操作大概率无法完成。
  • 若需要保存连接状态(如最后接收的消息ID),可在OnDestroy前将状态存入SharedPreferences,Service重启后读取恢复。

内容的提问来源于stack exchange,提问作者Velson Infotech

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 05:13:11