Nic*_*Guy 212 service android operating-system foreground android-8.0-oreo
我Service
在Android O OS上使用Class.
我计划Service
在后台使用.
Android建议指出startService()
应该使用startForegroundService()
.
如果您使用startForegroundService()
,则Service
抛出a Service
然后调用Service
错误.
这有什么问题?
小智 87
来自Google的Android 8.0上的文档行为更改:
即使应用程序在后台,系统也允许应用程序调用Context.startForegroundService().但是,应用程序必须在创建服务后的五秒内调用该服务的startForeground()方法.
解决方案:调用startForeground()
在onCreate()
为Service
您使用Context.startForegroundService()
另请参阅:Android 8.0的背景执行限制(奥利奥)
hum*_*zed 69
我打电话ContextCompat.startForegroundService(this, intent)
来启动服务
在服务中 onCreate
@Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= 26) {
String CHANNEL_ID = "my_channel_01";
NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
"Channel human readable title",
NotificationManager.IMPORTANCE_DEFAULT);
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("")
.setContentText("").build();
startForeground(1, notification);
}
}
Run Code Online (Sandbox Code Playgroud)
Zho*_*ouX 45
为什么会出现这个问题是因为Android框架无法保证您的服务在5秒内启动,但另一方面框架确实对前台通知有严格的限制必须在5秒内触发,而不检查框架是否曾尝试启动该服务.
这绝对是一个框架问题,但并非所有面临此问题的开发人员都在尽力:
startForeground通知必须同时在onCreate和onStartCommand中,因为如果您的服务已经创建,并且您的活动试图以某种方式再次启动它,则不会调用onCreate.
通知ID不能为0,否则会发生同样的崩溃,即使原因不一样.
不能在startForeground之前调用stopSelf.
有了以上所有3这个问题可以减少一点但仍然没有修复,真正的修复或让我们说解决方法是将目标sdk版本降级到25.
请注意,很可能Android P仍会出现此问题,因为Google拒绝了解发生了什么,并且不相信这是他们的错,请在此处阅读#36:https://issuetracker.google.com/issues/76112072.
swo*_*oby 23
如果你打电话给你的应用程序会崩溃Context.startForegroundService(...)
,然后调用Context.stopService(...)
之前Service.startForeground(...)
被调用.
我有一个明确的副本:https: //github.com/paulpv/ForegroundServiceAPI26/blob/repro/app/src/main/java/com/github/paulpv/foregroundserviceapi26/MainService.kt#L28
我已经在此处打开了一个错误:https: //issuetracker.google.com/issues/76112072
关于此的几个错误已经打开并关闭将不会修复.
希望采用明确的复制步骤进行复制.
Fur*_*kul 20
由于访问这里的每个人都遭受同样的事情,我想分享我之前没有人尝试过的解决方案(无论如何在这个问题中)。我可以向您保证它正在工作,即使在确认此方法的已停止断点上也是如此。
问题是Service.startForeground(id, notification)
从服务本身调用,对吗?不幸的是,Android Framework 不能保证在 5 秒Service.startForeground(id, notification)
内调用Service.onCreate()
,但无论如何都会抛出异常,所以我想出了这种方式。
Context.startForegroundService()
Context.startForegroundService()
则从服务连接调用,并立即在服务连接内部调用Service.startForeground()
。Context.bindService()
在try-catch 中调用该方法,因为在某些情况下调用可能会抛出异常,在这种情况下,您需要依靠Context.startForegroundService()
直接调用并希望它不会失败。一个例子可以是广播接收器上下文,但是在这种情况下获取应用程序上下文不会引发异常,但直接使用上下文会。当我在绑定服务之后和触发“startForeground”调用之前等待断点时,这甚至有效。等待 3-4 秒不会触发异常,而在 5 秒后抛出异常。(如果设备不能在 5 秒内执行两行代码,那么是时候把它扔进垃圾箱了。)
因此,从创建服务连接开始。
// Create the service connection.
ServiceConnection connection = new ServiceConnection()
{
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
// The binder of the service that returns the instance that is created.
MyService.LocalBinder binder = (MyService.LocalBinder) service;
// The getter method to acquire the service.
MyService myService = binder.getService();
// getServiceIntent(context) returns the relative service intent
context.startForegroundService(getServiceIntent(context));
// This is the key: Without waiting Android Framework to call this method
// inside Service.onCreate(), immediately call here to post the notification.
myService.startForeground(myNotificationId, MyService.getNotification());
// Release the connection to prevent leaks.
context.unbindService(this);
}
@Override
public void onBindingDied(ComponentName name)
{
Log.w(TAG, "Binding has dead.");
}
@Override
public void onNullBinding(ComponentName name)
{
Log.w(TAG, "Bind was null.");
}
@Override
public void onServiceDisconnected(ComponentName name)
{
Log.w(TAG, "Service is disconnected..");
}
};
Run Code Online (Sandbox Code Playgroud)
在您的服务中,创建一个返回服务实例的绑定器。
public class MyService extends Service
{
public class LocalBinder extends Binder
{
public MyService getService()
{
return MyService.this;
}
}
// Create the instance on the service.
private final LocalBinder binder = new LocalBinder();
// Return this instance from onBind method.
// You may also return new LocalBinder() which is
// basically the same thing.
@Nullable
@Override
public IBinder onBind(Intent intent)
{
return binder;
}
}
Run Code Online (Sandbox Code Playgroud)
然后,尝试从该上下文绑定服务。如果成功,它将ServiceConnection.onServiceConnected()
从您正在使用的服务连接调用方法。然后,处理上面显示的代码中的逻辑。示例代码如下所示:
// Try to bind the service
try
{
context.bindService(getServiceIntent(context), connection,
Context.BIND_AUTO_CREATE);
}
catch (RuntimeException ignored)
{
// This is probably a broadcast receiver context even though we are calling getApplicationContext().
// Just call startForegroundService instead since we cannot bind a service to a
// broadcast receiver context. The service also have to call startForeground in
// this case.
context.startForegroundService(getServiceIntent(context));
}
Run Code Online (Sandbox Code Playgroud)
它似乎在我开发的应用程序上工作,所以当你尝试时它也应该工作。
Ole*_*ryb 15
我知道,已经发布了太多答案,但是事实是-startForegroundService无法固定在应用程序级别,您应该停止使用它。Google建议在调用Context#startForegroundService()之后的5秒钟内使用Service#startForeground()API并不是应用程序总是可以做到的。
Android同时运行许多进程,并且无法保证Looper会在5秒钟内调用您应调用startForeground()的目标服务。如果目标服务在5秒钟内未收到呼叫,则说明您不走运,您的用户将遇到ANR情况。在堆栈跟踪中,您将看到以下内容:
Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{1946947 u0 ...MessageService}
main" prio=5 tid=1 Native
| group="main" sCount=1 dsCount=0 flags=1 obj=0x763e01d8 self=0x7d77814c00
| sysTid=11171 nice=-10 cgrp=default sched=0/0 handle=0x7dfe411560
| state=S schedstat=( 1337466614 103021380 2047 ) utm=106 stm=27 core=0 HZ=100
| stack=0x7fd522f000-0x7fd5231000 stackSize=8MB
| held mutexes=
#00 pc 00000000000712e0 /system/lib64/libc.so (__epoll_pwait+8)
#01 pc 00000000000141c0 /system/lib64/libutils.so (android::Looper::pollInner(int)+144)
#02 pc 000000000001408c /system/lib64/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+60)
#03 pc 000000000012c0d4 /system/lib64/libandroid_runtime.so (android::android_os_MessageQueue_nativePollOnce(_JNIEnv*, _jobject*, long, int)+44)
at android.os.MessageQueue.nativePollOnce (MessageQueue.java)
at android.os.MessageQueue.next (MessageQueue.java:326)
at android.os.Looper.loop (Looper.java:181)
at android.app.ActivityThread.main (ActivityThread.java:6981)
at java.lang.reflect.Method.invoke (Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1445)
Run Code Online (Sandbox Code Playgroud)
据我了解,Looper在这里分析了队列,找到了“滥用者”并干脆杀死了它。该系统现在是快乐和健康的,而开发人员和用户却不是,但是由于Google将其责任限制在该系统上,为什么他们要关心后两者?显然他们没有。他们可以做得更好吗?当然,例如,他们本可以为“应用程序忙”对话框提供服务,要求用户做出有关等待或终止该应用程序的决定,但是为什么要打扰,这不是他们的责任。最主要的是,该系统现在很健康。
根据我的观察,这种情况相对很少发生,以我为例,一千个用户在一个月内大约发生了1次崩溃。再现它是不可能的,即使再现它,也无法永久修复它。
在该线程中有一个很好的建议,即使用“ bind”而不是“ start”,然后在服务就绪时处理onServiceConnected,但是同样,这意味着完全不使用startForegroundService调用。
我认为,Google方面的正确和诚实的举动是告诉所有人startForegourndServcie有缺陷,不应使用。
问题仍然存在:用什么代替?对我们来说幸运的是,现在有JobScheduler和JobService,它们是前台服务的更好替代方案。因此,这是一个更好的选择,因为:
在作业运行时,系统代表您的应用程序持有唤醒锁。因此,您无需采取任何措施来保证设备在工作期间保持清醒状态。
这意味着您不再需要处理唤醒锁,这就是为什么它与前台服务没有什么不同的原因。从实现的角度来看,JobScheduler不是您的服务,它是系统的服务,大概它将处理队列权限,并且Google永远不会终止自己的孩子:)
三星已在其三星附件协议(SAP)中将startForegroundService切换为JobScheduler和JobService。当智能手表之类的设备需要与主机之类的设备进行通话时,这非常有用,因为工作确实需要通过应用程序的主线程与用户进行交互。由于作业由调度程序发布到主线程,因此成为可能。您应该记住,尽管该作业正在主线程上运行,并将所有繁重的工作转移到其他线程和异步任务上。
该服务在应用程序主线程上运行的Handler上执行每个传入的作业。这意味着您必须将执行逻辑卸载到您选择的另一个线程/处理程序/ AsyncTask
切换到JobScheduler / JobService的唯一陷阱是您需要重构旧代码,这很不好玩。我已经花了两天的时间来使用新的三星的SAP实施。我将查看崩溃报告,并让您知道是否再次看到崩溃。从理论上讲,这不应该发生,但是总有一些细节我们可能不知道。
更新 Play商店没有更多的崩溃报告。这意味着JobScheduler / JobService不会出现这样的问题,而切换到该模型是永远摆脱startForegroundService问题的正确方法。希望Google / Android能够阅读并最终为所有人提供评论/建议/提供正式指导。
Ahm*_*lan 14
我已经研究了几天并得到了解决方案.现在在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);
}
Run Code Online (Sandbox Code Playgroud)
而服务类应该是这样的
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
}
}
Run Code Online (Sandbox Code Playgroud)
Roy*_*erg 13
我有一个小部件,当设备处于清醒状态时会进行相对频繁的更新,并且我在短短几天内就看到了数千次崩溃.
我甚至在我的Pixel 3 XL上都注意到了这个问题,当时我根本不认为该设备有很多负载.并且覆盖了任何和所有代码路径startForeground()
.但后来我意识到,在很多情况下,我的服务很快就完成了工作.我相信我的应用程序的触发器是服务在系统实际到达显示通知之前完成.
我能够摆脱所有崩溃.我做的是删除对的呼叫stopSelf()
.(我在考虑延迟停止,直到我非常确定通知已显示,但我不希望用户在没有必要的情况下看到通知.)当服务闲置一分钟或系统时通常会破坏它而不会抛出任何异常.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
stopForeground(true);
} else {
stopSelf();
}
Run Code Online (Sandbox Code Playgroud)
tob*_*alr 10
只是一个抬头,因为我浪费了太多时间.即使我打电话startForeground(..)
给第一件事,我也一直得到这个例外onCreate(..)
.最后我发现问题是由于使用引起的NOTIFICATION_ID = 0
.使用任何其他值似乎解决了这个问题.
So many answer but none worked in my case.
我已经开始这样的服务。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent);
} else {
startService(intent);
}
Run Code Online (Sandbox Code Playgroud)
在我的 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);
}
Run Code Online (Sandbox Code Playgroud)
并且不要忘记设置 NOTIFICATION_ID 非零
private static final String ANDROID_CHANNEL_ID = "com.xxxx.Location.Channel";
private static final int NOTIFICATION_ID = 555;
Run Code Online (Sandbox Code Playgroud)
所以一切都很完美,但仍然在 8.1 上崩溃,所以原因如下。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
stopForeground(true);
} else {
stopForeground(true);
}
Run Code Online (Sandbox Code Playgroud)
我已经用 remove notificaton 调用了停止前台,但是一旦通知删除的服务成为后台,后台服务就无法从后台在 android O 中运行。收到推送后开始。
这么神奇的词是
stopSelf();
Run Code Online (Sandbox Code Playgroud)
到目前为止,您的服务崩溃的任何原因请按照上述所有步骤操作并享受。
使用目标 sdk 28 或更高版本时,您必须为 android 9 设备添加如下权限,否则将始终发生异常:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
Run Code Online (Sandbox Code Playgroud)
大约 10 个用户在我们的应用程序的 crashlytics 中遇到此错误。
正如 Kimi Chiu 回复的那样:这个问题的主要原因是服务在提升到前台之前就被停止了。但在服务被破坏后,断言并没有停止。您可以尝试通过在调用 startForegroundService-Kimi Chiu 后添加 StopService 来重现此问题
所以我对此进行了测试并能够重现。
我应用的一种解决方案是,让服务停留至少 5 秒,以便服务提升到前台。现在我在测试时无法重现该问题。
private fun stopService() {
lifecycleScope.launch {
delay(5000L)
try {
stopForeground(true)
isForeGroundService = false
stopSelf()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
Run Code Online (Sandbox Code Playgroud)
让我们看看这个问题是否会在我们的下一个版本中重现。
更新:)-> 这次没有与 Context.startForegroundService() 相关的问题,然后没有调用 Service.startForeground()
前后对比->
当id设置为0时调用Service.startForeground(int id,Notification notification)时,在Android 8+上也会发生此错误。
id int:根据NotificationManager.notify(int,Notification)的此通知的标识符;不能为0。
我已经解决了这个问题。我已经在自己的应用程序(300K + DAU)中验证了此修复程序,该修复程序可以减少至少95%的此类崩溃,但仍无法100%避免此问题。
即使您确定在Google记录服务启动后立即调用startForeground(),也会发生此问题。可能是因为在许多情况下服务创建和初始化过程已经花费了5秒钟以上的时间,因此无论何时何地调用startForeground()方法,这种崩溃都是不可避免的。
我的解决方案是确保startForegroundService()方法之后的5秒内将执行startForeground(),无论您的服务需要创建和初始化多长时间。这是详细的解决方案。
首先不要使用startForegroundService,而应将bindService()与auto_create标志一起使用。它将等待服务初始化。这是代码,我的示例服务是MusicService:
final Context applicationContext = context.getApplicationContext();
Intent intent = new Intent(context, MusicService.class);
applicationContext.bindService(intent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
if (binder instanceof MusicBinder) {
MusicBinder musicBinder = (MusicBinder) binder;
MusicService service = musicBinder.getService();
if (service != null) {
// start a command such as music play or pause.
service.startCommand(command);
// force the service to run in foreground here.
// the service is already initialized when bind and auto_create.
service.forceForeground();
}
}
applicationContext.unbindService(this);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}, Context.BIND_AUTO_CREATE);
Run Code Online (Sandbox Code Playgroud)然后是MusicBinder实现:
/**
* Use weak reference to avoid binder service leak.
*/
public class MusicBinder extends Binder {
private WeakReference<MusicService> weakService;
/**
* Inject service instance to weak reference.
*/
public void onBind(MusicService service) {
this.weakService = new WeakReference<>(service);
}
public MusicService getService() {
return weakService == null ? null : weakService.get();
}
}
Run Code Online (Sandbox Code Playgroud)最重要的部分,MusicService实现,forceForeground()方法将确保在startForegroundService()之后立即调用startForeground()方法:
public class MusicService extends MediaBrowserServiceCompat {
...
private final MusicBinder musicBind = new MusicBinder();
...
@Override
public IBinder onBind(Intent intent) {
musicBind.onBind(this);
return musicBind;
}
...
public void forceForeground() {
// API lower than 26 do not need this work around.
if (Build.VERSION.SDK_INT >= 26) {
Intent intent = new Intent(this, MusicService.class);
// service has already been initialized.
// startForeground method should be called within 5 seconds.
ContextCompat.startForegroundService(this, intent);
Notification notification = mNotificationHandler.createNotification(this);
// call startForeground just after startForegroundService.
startForeground(Constants.NOTIFICATION_ID, notification);
}
}
}
Run Code Online (Sandbox Code Playgroud)如果要以挂起的意图运行第1步代码段,例如,要在不打开应用程序的情况下在窗口小部件中启动前台服务(单击窗口小部件按钮),则可以将代码段包装在广播接收器中,并触发广播事件,而不是启动服务命令。
就这些。希望能帮助到你。祝好运。
我一直在研究这个问题,这是我迄今为止发现的。如果我们有类似的代码,可能会发生这种崩溃:
MyForegroundService.java
public class MyForegroundService extends Service {
@Override
public void onCreate() {
super.onCreate();
startForeground(...);
}
}
Run Code Online (Sandbox Code Playgroud)
主活动.java
Intent serviceIntent = new Intent(this, MyForegroundService.class);
startForegroundService(serviceIntent);
...
stopService(serviceIntent);
Run Code Online (Sandbox Code Playgroud)
在以下代码块中抛出异常:
活动服务.java
private final void bringDownServiceLocked(ServiceRecord r) {
...
if (r.fgRequired) {
Slog.w(TAG_SERVICE, "Bringing down service while still waiting for start foreground: "
+ r);
r.fgRequired = false;
r.fgWaiting = false;
mAm.mAppOpsService.finishOperation(AppOpsManager.getToken(mAm.mAppOpsService),
AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName);
mAm.mHandler.removeMessages(
ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
if (r.app != null) {
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_FOREGROUND_CRASH_MSG);
msg.obj = r.app;
msg.getData().putCharSequence(
ActivityManagerService.SERVICE_RECORD_KEY, r.toString());
mAm.mHandler.sendMessage(msg);
}
}
...
}
Run Code Online (Sandbox Code Playgroud)
此方法在之前执行onCreate()
,MyForegroundService
因为 Android 在主线程处理程序上安排服务的创建,但bringDownServiceLocked
在 a 上调用BinderThread
,这是一个竞争条件。这意味着MyForegroundService
没有机会调用startForeground
这将导致崩溃。
为了解决这个问题,我们必须确保bringDownServiceLocked
没有之前调用onCreate()
的MyForegroundService
。
public class MyForegroundService extends Service {
private static final String ACTION_STOP = "com.example.MyForegroundService.ACTION_STOP";
private final BroadcastReceiver stopReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
context.removeStickyBroadcast(intent);
stopForeground(true);
stopSelf();
}
};
@Override
public void onCreate() {
super.onCreate();
startForeground(...);
registerReceiver(
stopReceiver, new IntentFilter(ACTION_STOP));
}
@Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(stopReceiver);
}
public static void stop(Context context) {
context.sendStickyBroadcast(new Intent(ACTION_STOP));
}
}
Run Code Online (Sandbox Code Playgroud)
通过使用粘性广播,我们可以确保广播不会丢失,并且stopReceiver
一旦在onCreate()
of 中注册就接收到停止意图MyForegroundService
。此时我们已经调用了startForeground(...)
. 我们还必须删除粘性广播,以防止下次通知 stopReceiver。
请注意,该方法sendStickyBroadcast
已被弃用,我仅将其用作解决此问题的临时解决方法。
即使在调用startForeground
in后Service
,如果我们在调用stopService
之前调用,它也会在某些设备上崩溃。onCreate
因此,我通过使用附加标志启动服务来解决此问题:
Intent intent = new Intent(context, YourService.class);
intent.putExtra("request_stop", true);
context.startService(intent);
Run Code Online (Sandbox Code Playgroud)
并在 onStartCommand 中添加了一个检查,以查看它是否已开始停止:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//call startForeground first
if (intent != null) {
boolean stopService = intent.getBooleanExtra("request_stop", false);
if (stopService) {
stopSelf();
}
}
//Continue with the background task
return START_STICKY;
}
Run Code Online (Sandbox Code Playgroud)
PS 如果服务没有运行,它会先启动服务,这是一个开销。
请不要在onCreate()方法中调用任何 StartForgroundServices ,必须在创建工作线程后在onStartCommand() 中调用 StartForground 服务,否则总是会出现 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);
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:注意!startForeground 函数不能将 0 作为第一个参数,它会引发异常!此示例包含错误的函数调用,将 0 更改为您自己的常量,该常量不能为 0 或大于 Max(Int32)
来自 Google 关于Android 12 行为变化的文档:
To provide a streamlined experience for short-running foreground services on Android 12, the system can delay the display of foreground service notifications by 10 seconds for certain foreground services. This change gives short-lived tasks a chance to complete before their notifications appear.
Run Code Online (Sandbox Code Playgroud)
解决方案:在onCreate()中为您使用Context.startForegroundService()的Service调用startForeground()
归档时间: |
|
查看次数: |
110189 次 |
最近记录: |