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
相关产品推荐
相关产品推荐

