我在Android O操作系统上使用服务类。
我计划在后台使用服务。
Android文档指出
如果你的应用程序的API级别为26或更高,系统会对使用或创建后台服务施加限制,除非应用程序本身在前台。如果应用程序需要创建前台服务,应用程序应该调用startForegroundService()。
如果使用startForegroundService(),服务抛出以下错误。
Context.startForegroundService() did not then call
Service.startForeground()
这有什么问题?
很多答案,但没有一个对我有用。
我已经开始这样服务了。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent);
} else {
startService(intent);
}
在我的服务在onStartCommand
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Notification.Builder builder = new Notification.Builder(this, ANDROID_CHANNEL_ID)
.setContentTitle(getString(R.string.app_name))
.setContentText("SmartTracker Running")
.setAutoCancel(true);
Notification notification = builder.build();
startForeground(NOTIFICATION_ID, notification);
} else {
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setContentTitle(getString(R.string.app_name))
.setContentText("SmartTracker is Running...")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setAutoCancel(true);
Notification notification = builder.build();
startForeground(NOTIFICATION_ID, notification);
}
不要忘记将NOTIFICATION_ID设置为非零
private static final String ANDROID_CHANNEL_ID = "com.xxxx.Location.Channel";
private static final int NOTIFICATION_ID = 555;
所以一切都是完美的,但仍然崩溃在8.1,所以原因如下。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
stopForeground(true);
} else {
stopForeground(true);
}
我已经调用停止前台删除通知,但一旦通知删除服务成为后台和后台服务不能从后台运行在android O。在收到推送后启动。
神奇的词是
stopSelf();
到目前为止,任何原因你的服务崩溃遵循以上所有步骤,并享受。
大约有10个用户在我们的应用程序的崩溃分析中得到这个错误。
正如Kimi Chiu回答的那样:这个问题的主要原因是服务在提升到前台之前就停止了。但是断言在服务被销毁后并没有停止。你可以尝试在调用startforegroundservice后添加StopService来重现这个过程
所以我测试了这个,并得以复制。
我应用的一个解决方案是,我让服务至少停留5秒钟,这样服务就会提升到前台。现在我在测试时无法重现这个问题。
private fun stopService() {
lifecycleScope.launch {
delay(5000L)
try {
stopForeground(true)
isForeGroundService = false
stopSelf()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
让我们看看这个问题是否在我们的下一个构建中重现。
更新:)->这次没有与Context.startForegroundService()相关的问题,然后没有调用service . start前台()
之前/之后comparission - >
在- - - >
后- - - - - - >
现在在Android O,你可以设置后台限制如下
调用服务类的服务
Intent serviceIntent = new Intent(SettingActivity.this,DetectedService.class);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
SettingActivity.this.startForegroundService(serviceIntent);
} else {
startService(serviceIntent);
}
服务类应该是这样的
public class DetectedService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
@Override
public void onCreate() {
super.onCreate();
int NOTIFICATION_ID = (int) (System.currentTimeMillis()%10000);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForeground(NOTIFICATION_ID, new Notification.Builder(this).build());
}
// Do whatever you want to do here
}
}
请不要在onCreate()方法中调用任何StartForgroundServices,你必须在onStartCommand()中调用StartForground services,否则你将总是得到ANR,所以请不要在onStartCommand()的主线程中编写复杂的登录;
public class Services extends Service {
private static final String ANDROID_CHANNEL_ID = "com.xxxx.Location.Channel";
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Notification.Builder builder = new Notification.Builder(this, ANDROID_CHANNEL_ID)
.setContentTitle(getString(R.string.app_name))
.setContentText("SmartTracker Running")
.setAutoCancel(true);
Notification notification = builder.build();
startForeground(1, notification);
Log.e("home_button","home button");
} else {
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setContentTitle(getString(R.string.app_name))
.setContentText("SmartTracker is Running...")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setAutoCancel(true);
Notification notification = builder.build();
startForeground(1, notification);
Log.e("home_button_value","home_button_value");
}
return super.onStartCommand(intent, flags, startId);
}
}
编辑:小心!start前台函数不能以0作为第一个参数,它将引发异常!这个例子包含错误的函数调用,将0更改为你自己的const,它不能为0或大于Max(Int32)