Android Context.startForegroundService()然后没有调用Service.startForeground()
我正在安卓操作系统上使用Android Context.startForegroundService()然后没有调用Service.startForeground(),android,service,operating-system,foreground,android-8.0-oreo,Android,Service,Operating System,Foreground,Android 8.0 Oreo,我正在安卓操作系统上使用服务类 我计划在后台使用服务 国家 如果您的应用程序的目标API级别为26或更高,系统将对使用或创建后台服务施加限制,除非应用程序本身位于前台。如果应用程序需要创建前台服务,则应用程序应调用startForegroundService() 如果使用startForegroundService(),则服务将抛出以下错误 Context.startForegroundService()没有调用 Service.startForeground() 这有什么问题吗?来自谷歌的文
服务
类
我计划在后台使用服务
国家
如果您的应用程序的目标API级别为26或更高,系统将对使用或创建后台服务施加限制,除非应用程序本身位于前台。如果应用程序需要创建前台服务,则应用程序应调用startForegroundService()
如果使用startForegroundService()
,则服务将抛出以下错误
Context.startForegroundService()没有调用
Service.startForeground()
这有什么问题吗?来自谷歌的文档:
系统允许应用程序调用Context.startForegroundService(),即使应用程序处于后台。但是,应用程序必须在创建服务后的五秒钟内调用该服务的startForeground()方法
解决方案:
在onCreate()
中调用startForeground()
,用于使用Context.startForegroundService()
另请参见:对于Android 8.0(Oreo)我调用了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);
}
}
与startService(Intent)类似,但有一个隐含的承诺
服务将调用startForeground(int,android.app.Notification)一次
它开始运行。这项服务的时间相当
到ANR间隔执行此操作,否则系统将
自动停止服务并声明应用程序ANR
与普通startService(Intent)不同,此方法可在以下位置使用:
任何时候,无论承载服务的应用程序是否处于
前景状态
确保在onCreate()上调用服务.startForeground(int,android.app.Notification)
,以确保它将被调用。如果您有任何情况可能阻止您这样做,那么您最好使用正常的上下文.startService(Intent)
并调用服务.startForeground(int,android.app.Notification)
似乎Context.startForegroundService()
添加了一个看门狗,以确保您在销毁Service.startForeground(int,android.app.Notification)
之前调用了Service.startForegroundService(…)
,然后调用Context.stopService(…),您的应用程序将崩溃
在调用服务之前。startForeground(…)
我有一个明确的理由
我在以下位置打开了一个错误:
此上的几个错误已打开和关闭,无法修复
希望我有清晰的复制步骤能成功
谷歌团队提供的信息
这不是框架错误;这是故意的。如果应用程序使用startForegroundService()
启动服务实例,它必须将该服务实例转换为前台状态并显示通知。如果服务实例在startForeground()之前停止
被调用,这个承诺没有实现:这是应用程序中的一个bug
,发布其他应用程序可以直接启动的服务从根本上说是不安全的。您可以通过将该服务的所有启动操作视为需要startForeground()
,来减轻这一点,但显然这可能不是您的想法
这里有两种不同的情况导致相同的结果
直接的语义问题是,使用startForegroundService()
启动某项服务只是一个错误,而忽略了通过startForeground()将其实际转换到前台
,只是:语义问题。故意将其视为应用程序错误。在将服务转换到前台之前停止服务是一个应用程序错误。这是操作的关键,也是为什么此问题被标记为“按预期工作”的原因
然而,关于这个问题的虚假检测也存在一些问题。这被视为一个真正的问题,尽管它与这个特定的bug追踪器问题是分开跟踪的。我们对投诉并不充耳不闻。我对此研究了几天,并得到了解决方案。
现在在androido中,您可以如下设置背景限制
调用服务类的服务
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中,否则请使用意向服务
,然后将此代码放入OnHandleContent中
if (Build.VERSION.SDK_INT >= 26) {
String CHANNEL_ID = "my_app";
NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
"MyApp", NotificationManager.IMPORTANCE_DEFAULT);
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("")
.setContentText("").build();
startForeground(1, notification);
}
提醒一下,我在这上面浪费了太多的时间。尽管我在onCreate(…)
中第一件事就是调用startForeground(…)
,但我还是不断得到这个异常。
最后我发现这个问题是由于使用了通知\u ID=0
造成的。使用任何其他值似乎都可以解决这个问题。当ID设置为0时调用Android 8+时,这个错误也会发生
id int:根据NotificationManager,此通知的标识符。notify(int,notification);不能为0
之所以会出现这个问题,是因为Android框架无法保证您的服务在5秒内启动,但另一方面,框架对前台通知必须在5秒内启动有严格限制,而不检查框架是否尝试启动服务
这肯定是一个框架问题,但并非所有面临此问题的开发人员都在竭尽全力:
startForeground
通知必须同时位于onCreate
和onStartCommand
中,因为如果您的服务已经是crea
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent);
} else {
startService(intent);
}
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);
}
private static final String ANDROID_CHANNEL_ID = "com.xxxx.Location.Channel";
private static final int NOTIFICATION_ID = 555;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
stopForeground(true);
} else {
stopForeground(true);
}
stopSelf();
Intent intent = new Intent(context, YourService.class);
intent.putExtra("request_stop", true);
context.startService(intent);
@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;
}
if (Util.SDK_INT > 26) {
mContext.startForegroundService(playIntent);
} else {
mContext.startService(playIntent);
}
mContext.startService(playIntent);
PendingIntent pendingIntent=PendingIntent.getBroadcast(context,0,intent,PendingIntent.FLAG_NO_CREATE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && pendingIntent==null){
context.startForegroundService(service_intent);
}
else
{
context.startService(service_intent);
}
}
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);
/**
* 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();
}
}
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);
}
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
stopForeground(true);
} else {
stopSelf();
}
public class MyForegroundService extends Service {
@Override
public void onCreate() {
super.onCreate();
startForeground(...);
}
}
Intent serviceIntent = new Intent(this, MyForegroundService.class);
startForegroundService(serviceIntent);
...
stopService(serviceIntent);
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);
}
}
...
}
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));
}
}
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);
}
}
import android.app.Notification;
public class AuthenticationService extends Service {
@Override
public void onCreate() {
super.onCreate();
startForeground(1,new Notification());
}
}
class TestService : Service() {
override fun onCreate() {
super.onCreate()
Log.d(TAG, "onCreate")
val nBuilder = NotificationCompat.Builder(this, "all")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle("TestService")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
startForeground(1337, nBuilder.build())
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val rtn = super.onStartCommand(intent, flags, startId)
if (intent?.action == STOP_ACTION) {
Log.d(TAG, "onStartCommand -> STOP")
stopForeground(true)
stopSelf()
} else {
Log.d(TAG, "onStartCommand -> START")
}
return rtn
}
override fun onDestroy() {
Log.d(TAG, "onDestroy")
super.onDestroy()
}
override fun onBind(intent: Intent?): IBinder? = null
companion object {
private val TAG = "TestService"
private val STOP_ACTION = "ly.zen.test.TestService.ACTION_STOP"
fun start(context: Context) {
ContextCompat.startForegroundService(context, Intent(context, TestService::class.java))
}
fun stop(context: Context) {
val intent = Intent(context, TestService::class.java)
intent.action = STOP_ACTION
ContextCompat.startForegroundService(context, intent)
}
}
}
val nChannel = NotificationChannel("all", "All", NotificationManager.IMPORTANCE_NONE)
val nManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
nManager.createNotificationChannel(nChannel)
start_test_service.setOnClickListener {
TestService.start(this@MainActivity)
TestService.stop(this@MainActivity)
}
D/TestService: onCreate
D/TestService: onStartCommand -> START
D/TestService: onStartCommand -> STOP
D/TestService: onDestroy
context?.bindService(
Intent(context, AudioService::class.java),
serviceConnection, Context.BIND_AUTO_CREATE)
ContextCompat.startForegroundService(
context!!,
Intent(context, AudioService::class.java).apply {
action = CONTENT_SELECTED_ACTION
putExtra(CONTENT_SELECTED_KEY, contentToPlay.content.apply {
audioUrl = uri.toString()
})
})
private var uri: Uri = Uri.parse("")
override fun onBind(intent: Intent?) =
AudioServiceBinder().apply {
player = ExoPlayerFactory.newSimpleInstance(
applicationContext,
AudioOnlyRenderersFactory(applicationContext),
DefaultTrackSelector())
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
intent?.let {
when (intent.action) {
CONTENT_SELECTED_ACTION -> it.getParcelableExtra<Content>(CONTENT_SELECTED_KEY).also { content ->
val intentUri = Uri.parse(content.audioUrl)
// Checks whether to update Uri passed in Intent Bundle.
if (!intentUri.equals(uri)) {
uri = intentUri
player?.prepare(ProgressiveMediaSource.Factory(
DefaultDataSourceFactory(
this,
Util.getUserAgent(this, getString(app_name))))
.createMediaSource(uri))
player?.playWhenReady = true
// Calling 'startForeground' in 'buildNotification(...)'.
buildNotification(intent.getParcelableExtra(CONTENT_SELECTED_KEY))
}
}
}
}
return super.onStartCommand(intent, flags, startId)
}
// Calling 'startForeground' in 'onNotificationStarted(...)'.
private fun buildNotification(content: Content): Unit? {
playerNotificationManager = PlayerNotificationManager.createWithNotificationChannel(
this,
content.title,
app_name,
if (!content.audioUrl.isNullOrEmpty()) 1 else -1,
object : PlayerNotificationManager.MediaDescriptionAdapter {
override fun createCurrentContentIntent(player: Player?) = ...
override fun getCurrentContentText(player: Player?) = ...
override fun getCurrentContentTitle(player: Player?) = ...
override fun getCurrentLargeIcon(player: Player?,
callback: PlayerNotificationManager.BitmapCallback?) = ...
},
object : PlayerNotificationManager.NotificationListener {
override fun onNotificationStarted(notificationId: Int, notification: Notification) {
startForeground(notificationId, notification)
}
override fun onNotificationCancelled(notificationId: Int) {
stopForeground(true)
stopSelf()
}
})
return playerNotificationManager.setPlayer(player)
}
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)
SAAgentV2.requestAgent(App.app?.applicationContext,
MessageJobs::class.java!!.getName(), mAgentCallback)
SAAgentV2.d var3 = new SAAgentV2.d(var0, var1, var2);
where d defined as below
private SAAdapter d;
SAJobService.scheduleSCJob(SAAdapter.this.d, var11, var14, var3, var12);
private static void a(Context var0, String var1, String var2, long var3, String var5, SAPeerAgent var6) {
ComponentName var7 = new ComponentName(var0, SAJobService.class);
Builder var10;
(var10 = new Builder(a++, var7)).setOverrideDeadline(3000L);
PersistableBundle var8;
(var8 = new PersistableBundle()).putString("action", var1);
var8.putString("agentImplclass", var2);
var8.putLong("transactionId", var3);
var8.putString("agentId", var5);
if (var6 == null) {
var8.putStringArray("peerAgent", (String[])null);
} else {
List var9;
String[] var11 = new String[(var9 = var6.d()).size()];
var11 = (String[])var9.toArray(var11);
var8.putStringArray("peerAgent", var11);
}
var10.setExtras(var8);
((JobScheduler)var0.getSystemService("jobscheduler")).schedule(var10.build());
}
private val mAgentCallback = object : SAAgentV2.RequestAgentCallback {
override fun onAgentAvailable(agent: SAAgentV2) {
mMessageService = agent as? MessageJobs
App.d(Accounts.TAG, "Agent " + agent)
}
override fun onError(errorCode: Int, message: String) {
App.d(Accounts.TAG, "Agent initialization error: $errorCode. ErrorMsg: $message")
}
}
class MessageJobs (context:Context) : SAAgentV2(SERVICETAG, context, MessageSocket::class.java) {
public fun release () {
}
override fun onServiceConnectionResponse(p0: SAPeerAgent?, p1: SASocket?, p2: Int) {
super.onServiceConnectionResponse(p0, p1, p2)
App.d(TAG, "conn resp " + p1?.javaClass?.name + p2)
}
override fun onAuthenticationResponse(p0: SAPeerAgent?, p1: SAAuthenticationToken?, p2: Int) {
super.onAuthenticationResponse(p0, p1, p2)
App.d(TAG, "Auth " + p1.toString())
}
override protected fun onServiceConnectionRequested(agent: SAPeerAgent) {
}
}
override fun onFindPeerAgentsResponse(peerAgents: Array<SAPeerAgent>?, result: Int) {
}
override fun onError(peerAgent: SAPeerAgent?, errorMessage: String?, errorCode: Int) {
super.onError(peerAgent, errorMessage, errorCode)
}
override fun onPeerAgentsUpdated(peerAgents: Array<SAPeerAgent>?, result: Int) {
}
}
context.startForegroundService(new Intent(context, TaskQueueExecutorService.class));
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Handler(Looper.getMainLooper()).post(new Runnable() {
public void run() {
context.startForegroundService(new Intent(context,
TaskQueueExecutorService.class));
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
@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("")
.setColor(ContextCompat.getColor(this, R.color.transparentColor))
.setSmallIcon(ContextCompat.getColor(this, R.color.transparentColor)).build();
startForeground(1, notification);
}
}
// 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..");
}
};
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;
}
}
// 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));
}
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
Context.startForegroundService() did not then call Service.startForeground();
....//some other code
...// API level and other device auto star service condition is already set
stopService();
startService();
.....//some other code
new Handler().postDelayed(()->ContextCompat.startForegroundService(activity, new Intent(activity, ChatService.class)), 500);
<service
android:name=".AudioRecorderService"
android:enabled="true"
android:exported="false"
android:foregroundServiceType="microphone" />
public class AService extends Service {
@Override
public void onCreate() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
startForeground(
getForegroundNotificationId(),
channelManager.buildBackgroundInfoNotification(getNotificationTitle(), getNotificationText()),
ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC);
} else {
startForeground(getForegroundNotificationId(),
channelManager.buildBackgroundInfoNotification(getNotificationTitle(), getNotificationText())
);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
startForeground();
if (hasQueueMoreItems()) {
startWorkerThreads();
} else {
stopForeground(true);
stopSelf();
}
return START_STICKY;
}
private class WorkerRunnable implements Runnable {
@Override
public void run() {
while (getItem() != null && !isLoopInterrupted) {
doSomething(getItem())
}
waitALittle();
stopForeground(true);
stopSelf();
}
private void waitALittle() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
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.