如何让Android后台服务每小时运行,即使应用被强制关闭?
我明白你的需求:让网络检测服务每小时跑一次,哪怕应用被从最近列表里强制关掉。咱们先看看现有代码的问题,再一步步解决~
现有代码的局限
你当前的NetworkService只是在应用启动时被调用一次,没有定时触发的逻辑;而且普通Service在Android 8.0+的系统中,应用退到后台或被强关后很容易被系统回收,没法保证持续运行。
推荐方案:用WorkManager实现可靠的周期性任务
Google官方推荐使用WorkManager来处理这类需要定时、可靠执行的后台任务,它能自动适配不同Android版本的后台限制,即使应用被关闭、设备重启(可选配置),任务也能继续执行。
步骤1:添加WorkManager依赖
在你的build.gradle(Module level)里添加依赖(根据你的Android Gradle Plugin版本调整,这里用最新稳定版示例):
dependencies { implementation "androidx.work:work-runtime:2.8.1" }
步骤2:创建网络检测Worker类
替代原来的NetworkService,创建一个继承自Worker的类,把网络检测逻辑放在这里:
using System.IO; using Android.App; using Android.Content; using Android.Net; using AndroidX.Work; namespace example.Services { public class NetworkCheckWorker : Worker { public NetworkCheckWorker(Context context, WorkerParameters workerParams) : base(context, workerParams) { } public override Result DoWork() { // 执行网络检测逻辑 string filename = "network.txt"; var documentsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal); var filePath = Path.Combine(documentsPath, filename); if (!File.Exists(filePath)) File.Create(filePath).Close(); // 记得Close,否则会占用文件 ConnectivityManager connectivityManager = (ConnectivityManager)ApplicationContext.GetSystemService(Context.ConnectivityService); bool isOnline = false; // 适配Android 10+的Network API(旧的NetworkInfo已被废弃) if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.M) { var network = connectivityManager.ActiveNetwork; var capabilities = connectivityManager.GetNetworkCapabilities(network); isOnline = capabilities != null && (capabilities.HasTransport(TransportType.Wifi) || capabilities.HasTransport(TransportType.Cellular)); } else { var networkInfo = connectivityManager.ActiveNetworkInfo; isOnline = networkInfo != null && networkInfo.IsConnected; } File.WriteAllText(filePath, isOnline ? "Connected" : "Not Connected"); // 返回Result.Success表示任务执行成功,系统会按计划继续下一次 return Result.InvokeSuccess(); } } }
注意:这里适配了Android 6.0+的新Network API,因为旧的
NetworkInfo已经被废弃了,这样代码兼容性更好。
步骤3:配置并启动周期性任务
在你的MainActivity里,初始化WorkManager的周期性请求,设置每小时执行一次:
using Android.App; using Android.Content; using Android.OS; using Android.Widget; using AndroidX.Work; namespace whitesrecycling.Activities { [Activity(Label = "HomeActivity")] public class HomeActivity : Activity { protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); SetContentView(Resource.Layout.Home); var toolbar = FindViewById<Toolbar>(Resource.Id.toolbar); SetActionBar(toolbar); ActionBar.Title = "Example"; // 启动周期性网络检测任务 StartPeriodicNetworkCheck(); } private void StartPeriodicNetworkCheck() { // 设置任务约束(可选,比如只在有网络时执行) var constraints = new Constraints.Builder() .SetRequiredNetworkType(NetworkType.Connected) // 可选,根据需求调整 .Build(); // 创建每小时执行一次的周期性请求 var periodicWorkRequest = new PeriodicWorkRequest.Builder( typeof(NetworkCheckWorker), System.TimeSpan.FromHours(1), // 间隔时间 System.TimeSpan.FromMinutes(10)) // 弹性窗口(允许系统在这个窗口内调整执行时间,优化电池) .SetConstraints(constraints) .Build(); // 将任务提交给WorkManager WorkManager.GetInstance(ApplicationContext).EnqueueUniquePeriodicWork( "NetworkCheckTask", ExistingPeriodicWorkPolicy.Keep, // 如果任务已存在,保留原任务 periodicWorkRequest); } } }
步骤4:移除旧的Service配置
现在你不需要原来的NetworkService了,可以删掉它,同时从AndroidManifest.xml里移除对应的<service>配置。
关键说明
为什么不用AlarmManager+Service?
Android 8.0之后,后台Service有严格的限制,应用进入后台后5分钟内Service会被系统停止,AlarmManager的定时任务在后台也可能被延迟或忽略。WorkManager会自动处理这些限制,选择最优的执行方式(比如在API 23+用JobScheduler,API 14-22用AlarmManager+BroadcastReceiver)。设备重启后任务是否继续?
WorkManager默认会在设备重启后恢复任务,不需要额外配置(前提是应用已经被打开过至少一次)。任务执行的弹性窗口
PeriodicWorkRequest的第二个参数是间隔时间,第三个是弹性窗口,系统会在这个窗口内选择合适的时间执行任务,减少对电池的消耗。如果需要严格准时执行,可以用OneTimeWorkRequest结合链式调用,但会增加电池消耗,不推荐。
内容的提问来源于stack exchange,提问作者Gurpreet Bhopal

