面向Nougat的App使用startService()是否有效?如何适配Oreo?
关于Nougat/Oreo下位置服务启动与适配的问题解答
1. 面向Nougat(API25)使用startService()是否正常?
完全没问题!Android对后台服务的严格限制是从**Oreo(API26)**才开始推行的,Nougat及更低版本的系统并没有这个限制。你当前的代码在targetSdkVersion=25的环境下,调用startService()启动LocationUpdateService并设置START_STICKY,可以正常在后台持续运行,不需要做额外修改。
2. 适配Oreo(API26+)系统需要做哪些修改?
Oreo引入了后台服务限制,直接调用startService()会抛出IllegalStateException,所以得做这几处关键修改:
- 替换服务启动方式:当系统版本是Oreo及以上时,必须用
startForegroundService()替代startService(),但要注意:调用这个方法后,必须在5秒内调用startForeground()显示一个前台通知,否则系统会直接杀死你的服务。 - 添加前台通知逻辑:在你的
LocationUpdateService中,需要创建通知渠道(Oreo强制要求)并构建前台通知,示例代码如下:
private static final int LOCATION_NOTIFICATION_ID = 1001; private static final String CHANNEL_ID = "location_update_channel"; @Override public void onCreate() { super.onCreate(); // 适配Oreo及以上的通知渠道 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "位置更新服务", NotificationManager.IMPORTANCE_LOW); NotificationManager manager = getSystemService(NotificationManager.class); if (manager != null) { manager.createNotificationChannel(channel); } } } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "onStartCommand: "); mLocationRequest = new LocationRequest(); mLocationRequest.setInterval(BACKGROUND_INTERVAL); mLocationRequest.setFastestInterval(BACKGROUND_INTERVAL); mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY); // 启动前台服务 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID) .setContentTitle("位置服务运行中") .setContentText("正在更新你的位置信息") .setSmallIcon(R.drawable.ic_location) .build(); startForeground(LOCATION_NOTIFICATION_ID, notification); } super.onStartCommand(intent, flags, startId); return START_STICKY; }
- 考虑更优的后台方案:如果你的服务只是做周期性位置更新,建议使用
WorkManager或者FusedLocationProviderClient的前台模式,这些组件更符合Android后续版本的后台规范,能降低被系统回收的概率。
3. 为什么compileSdkVersion 25无法调用startForegroundService()?
因为startForegroundService()是API26才新增的方法,而compileSdkVersion决定了你能访问的Android SDK API范围。如果你的compileSdkVersion停留在25,IDE和编译工具会认为这个方法不存在,自然无法调用。
解决办法很简单:
- 把
build.gradle中的compileSdkVersion升级到26或更高(建议用最新稳定版),同时可以把targetSdkVersion也升到26+,这样就能正常调用该方法了。 - 为了兼容低版本系统,启动服务时要做版本判断,修改你的
initLocationService()方法:
private void initLocationService() { locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); if(getPermissions(android.Manifest.permission.ACCESS_FINE_LOCATION,GET_LOCATION_PERMISSION)){ Intent serviceIntent = new Intent(HomeActivity.this, LocationUpdateService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(serviceIntent); } else { startService(serviceIntent); } } }
内容的提问来源于stack exchange,提问作者dev90
相关产品推荐
相关产品推荐

