Android 安卓O-旧版启动前台服务仍在运行?
因此,使用安卓O,如果您希望每小时接收的位置更新不止几个,那么您需要将您的服务作为前台服务运行 我注意到,启动前台服务的旧方法似乎在O。 i、 e 根据此处的行为改变指南: 方法启动前台服务。启动前台服务的旧方法不再有效 尽管新方法仅在目标为O时有效,但无论是否针对O,旧方法似乎仍然适用于O设备 编辑 包括示例: Google示例项目LocationUpdatesForegroundsService实际上有一个工作示例,您可以直接看到这个问题。 无论是针对API级别25的目标和编译,还是针对O的目标和编译,startForeground方法似乎都可以正常工作(如下所述:) 因此,复制:Android 安卓O-旧版启动前台服务仍在运行?,android,location,android-8.0-oreo,Android,Location,Android 8.0 Oreo,因此,使用安卓O,如果您希望每小时接收的位置更新不止几个,那么您需要将您的服务作为前台服务运行 我注意到,启动前台服务的旧方法似乎在O。 i、 e 根据此处的行为改变指南: 方法启动前台服务。启动前台服务的旧方法不再有效 尽管新方法仅在目标为O时有效,但无论是否针对O,旧方法似乎仍然适用于O设备 编辑 包括示例: Google示例项目LocationUpdatesForegroundsService实际上有一个工作示例,您可以直接看到这个问题。 无论是针对API级别25的目标和编译,还是针对
服务正在前台运行(通过通知阴影中的图标显示)。即使在运行O的设备上,位置更新也会按预期进行(每10秒一次)。我这里缺少的是什么?通常您使用
startService从广播接收器启动服务。他们说调用startService
不再可能(或可靠),因为现在存在后台限制,所以您需要调用startServiceInForeground
。然而,从文档中还不清楚什么时候会发生,因为当应用程序收到广播意图时会被列入白名单,因此,现在还不清楚什么时候启动前台服务会抛出非法状态异常。当应用程序位于前台时,启动前台服务的传统方法仍然有效,但建议针对API级别26/Android O的应用程序启动前台服务的方法是使用新引入的NotificationManager#首先启动ServiceInforeGround方法来创建前台服务
由于Android O的后台执行限制,如果应用程序处于后台模式,那么在后台启动服务然后将其升级到前台的旧方法将不起作用
这里记录了迁移过程和步骤 这对我很有效
在活动类中,使用startForegroundService()而不是startService()启动服务
现在在onStartCommand()的服务类中执行以下操作
注意:使用Notification.Builder而不是NotificationCompat.Builder使其工作正常。仅在Notification.Builder中,您需要提供频道ID,这是Android Oreo中的新功能
希望它能起作用
编辑:
如果您的目标API级别为28或更高,则需要前台服务权限,否则,您的应用程序将崩溃
只需将其添加到AndroidManifest.xml文件中
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
如果需要,我可以使用Backback builder添加示例
val notifyManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
val playIntent = Intent(this, this::class.java).setAction(PAUSE)
val cancelIntent = Intent(this, this::class.java).setAction(EXIT)
val stop = PendingIntent.getService(this, 1, playIntent, PendingIntent.FLAG_UPDATE_CURRENT)
val exit = PendingIntent.getService(this, 2, cancelIntent, PendingIntent.FLAG_UPDATE_CURRENT)
val builder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notifyManager.createNotificationChannel(NotificationChannel(NOTIFICATION_ID_CHANNEL_ID, getString(R.string.app_name), NotificationManager.IMPORTANCE_HIGH))
NotificationCompat.Builder(this, NOTIFICATION_ID_CHANNEL_ID)
} else
NotificationCompat.Builder(this)
builder.apply {
setContentTitle(station.name)
setContentText(metaToText(meta) )
setSmallIcon(R.drawable.ic_play_arrow_white_24px)
setAutoCancel(false)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) priority = Notification.PRIORITY_MAX
addAction(R.drawable.ic_stop_white_24px, getString(R.string.player_notification_stop), stop)
addAction(R.drawable.ic_close_white_24px, getString(R.string.player_notification_exit), exit)
}
val stackBuilder = TaskStackBuilder.create(this)
stackBuilder.addParentStack(PlayerActivity::class.java)
stackBuilder.addNextIntent(Intent(this, PlayerActivity::class.java))
builder.setContentIntent(stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT))
startForeground(NOTIFICATION_ID, builder.build())
val notifyManager=getSystemService(通知服务)作为NotificationManager
val playIntent=Intent(this,this::class.java).setAction(暂停)
val cancelIntent=Intent(this,this::class.java).setAction(EXIT)
val stop=pendingent.getService(this,1,playtintent,pendingent.FLAG_UPDATE_CURRENT)
val exit=PendingEvent.getService(此,2,cancelIntent,PendingEvent.FLAG_更新_当前)
val builder=if(Build.VERSION.SDK\u INT>=Build.VERSION\u code.O){
notifyManager.createNotificationChannel(NotificationChannel(通知\u ID\u通道\u ID,getString(R.string.app\u名称),NotificationManager.IMPORTANCE\u HIGH))
NotificationCompat.Builder(此,通知ID\u通道ID)
}否则
NotificationCompat.Builder(此)
builder.apply{
setContentTitle(station.name)
setContentText(metaToText(meta))
设置小图标(右可绘制。ic_播放_箭头_白色_24px)
设置自动取消(错误)
if(Build.VERSION.SDK\u INT
正如@Kislingk在注释NotificationManager中提到的那样。startServiceInForeground
已被删除。它被标记为已弃用,并带有
从提交消息:
而不是要求提供先验通知,以便
直接将服务启动到前台状态,我们采用两阶段
复合操作,即使是从
后台执行状态。上下文#startForegroundService()不可用
受背景限制,要求
服务通过内部的startForeground()正式进入前台状态
5秒。如果服务不这样做,操作系统和
该应用程序因服务ANR而受到指责
在活动(或启动前台服务的任何上下文)中,调用以下命令:
Intent Intent=newintent(这个,MyService.class)
ContextCompat.startForegroundService(上下文、意图);
服务启动后,使用与以下内容类似的代码创建通知通道:
@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(text)
.setAutoCancel(true);
Notification notification = builder.build();
startForeground(1, notification);
} else {
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setContentTitle(getString(R.string.app_name))
.setContentText(text)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setAutoCancel(true);
Notification notification = builder.build();
startForeground(1, notification);
}
return START_NOT_STICKY;
}
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
val notifyManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
val playIntent = Intent(this, this::class.java).setAction(PAUSE)
val cancelIntent = Intent(this, this::class.java).setAction(EXIT)
val stop = PendingIntent.getService(this, 1, playIntent, PendingIntent.FLAG_UPDATE_CURRENT)
val exit = PendingIntent.getService(this, 2, cancelIntent, PendingIntent.FLAG_UPDATE_CURRENT)
val builder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notifyManager.createNotificationChannel(NotificationChannel(NOTIFICATION_ID_CHANNEL_ID, getString(R.string.app_name), NotificationManager.IMPORTANCE_HIGH))
NotificationCompat.Builder(this, NOTIFICATION_ID_CHANNEL_ID)
} else
NotificationCompat.Builder(this)
builder.apply {
setContentTitle(station.name)
setContentText(metaToText(meta) )
setSmallIcon(R.drawable.ic_play_arrow_white_24px)
setAutoCancel(false)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) priority = Notification.PRIORITY_MAX
addAction(R.drawable.ic_stop_white_24px, getString(R.string.player_notification_stop), stop)
addAction(R.drawable.ic_close_white_24px, getString(R.string.player_notification_exit), exit)
}
val stackBuilder = TaskStackBuilder.create(this)
stackBuilder.addParentStack(PlayerActivity::class.java)
stackBuilder.addNextIntent(Intent(this, PlayerActivity::class.java))
builder.setContentIntent(stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT))
startForeground(NOTIFICATION_ID, builder.build())
final Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID).setSmallIcon(...)//
.setPriority(...).setCategory(...).setContentTitle(...).setContentText(...).setTicker(...);
// and maybe other preparations to the notification...
startForeground(notificationId, builder.build());
OneTimeWorkRequest work =
new OneTimeWorkRequest.Builder(MyWorker.class)
.build();
WorkManager.getInstance().enqueue(work);
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
var service = Intent(context, AnyService::class.java)
context?.startForegroundService(service)
} else {
var service = Intent(context, AnyService::class.java)
context?.startService(service)
}
class AnyService : Service() {
override fun onBind(intent: Intent?): IBinder? {
}
override fun onCreate() {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O)
startMyOwnForeground()
else
startForeground(1, Notification())
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return START_STICKY
}
override fun onDestroy() {
super.onDestroy()
}
@RequiresApi(Build.VERSION_CODES.O)
private fun startMyOwnForeground() {
val NOTIFICATION_CHANNEL_ID = "example.permanence"
val channelName = "Background Service"
val chan = NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_NONE)
chan.lightColor = Color.BLUE
chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
manager.createNotificationChannel(chan)
val notificationBuilder = NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
val notification = notificationBuilder.setOngoing(true)
.setContentTitle("App is running in background")
.setPriority(NotificationManager.IMPORTANCE_MIN)
.setCategory(Notification.CATEGORY_SERVICE)
.build()
startForeground(2, notification)
}