Fatal Exception: android.app.ForegroundServiceDidNotStartInTimeException: Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{294bdda u0 com.xyz.xyz/com.xyz.pushnotification.BookingProgressService}
at android.app.ActivityThread.throwRemoteServiceException(ActivityThread.java:1923)
at android.app.ActivityThread.access$2700(ActivityThread.java:247)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2148)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7839)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
I'm facing this crash inside my service and that i have wrote on below way
Start service:
if (Build.VERSION.SDK_INT >= 26)
mContext.startForegroundService(serviceIntent)
else
mContext.startService(serviceIntent)
Inside Time Tick update or create notification:
registerTimeTickReceiver() method called inside onStartCommand() of Service class
private fun registerTimeTickReceiver() {
if (timeTickReceiver != null)
unregisterTimeTickReceiver()
timeTickReceiver = object : BroadcastReceiver() {
override fun onReceive(
context: Context, intent: Intent
) { //trigger the callback on every minutes
Log.e("BookingProgressService", "Service registerTimeTickReceiver")
if (intent.action?.compareTo(Intent.ACTION_TIME_TICK) == 0)
fetchDataForNotification()
}
}
registerReceiver(timeTickReceiver, IntentFilter(Intent.ACTION_TIME_TICK))
}
Inside fetchDataForNotification() added:
startForeground(booking.id, notification)
Note: This crashes I can't able to reproduce from my device but it is reproduced on some of the devices
My requirement is update multiple booking progress notification on every minute If my app is running or not running(Background) Can anyone please help me? or If you know other best approach then very thankful to you guys
Related
I have a service receiver to take care of callbacks related to BLE GATT events (connecting, disconnecting, etc).
In situations where I kill the BLE device to simulate a dropout, the disconnect event fires, and my call to context.unbindService(serviceConnection) fails. I've checked for a few of the obvious errors (different contexts, null service connection, etc), and can't find the error. Why am I getting this exception?
Here's the trace:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.ktest, PID: 6372
java.lang.IllegalArgumentException: Service not registered: com.example.ktest.ble.BLEConnectionManager$serviceConnection$1#493960
at android.app.LoadedApk.forgetServiceDispatcher(LoadedApk.java:1602)
at android.app.ContextImpl.unbindService(ContextImpl.java:1710)
at android.content.ContextWrapper.unbindService(ContextWrapper.java:717)
at com.example.ktest.ble.BLEConnectionManager.unBindService(BLEConnectionManager.kt:81)
at com.example.ktest.foo.FooActivity.disconnect(FooActivity.kt:268)
at com.example.ktest.foo.FooActivity.access$disconnect(FooActivity.kt:47)
at com.example.ktest.foo.FooActivity$gattUpdateReceiver$1$onReceive$1.run(FooActivity.kt:190)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6863)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:537)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Here's the disconnect function that's called as per the trace:
private fun disconnect() {
BLEConnectionManager.unBindService(this#FooActivity) // FAILS HERE
unregisterServiceReceiver()
val intent = Intent(this, ConnectDeviceActivity::class.java)
startActivity(intent)
finish() // close activity
}
The service was bound using the same context (from FooActivity.onStart()):
BLEConnectionManager.bindService(this#FooActivity)
So there are no problems when BLEConnectionManager.bindService() is called:
fun bindService(context: Context) {
if (serviceConnection != null && isBound) {
Log.w(TAG, "Service is already bound")
} else {
val gattServiceIntent = Intent(context, BLEService::class.java)
if (context != null) {
isBound = context.bindService(
gattServiceIntent,
serviceConnection,
Context.BIND_AUTO_CREATE)
}
Log.i(TAG, "BLEService now bound, isBound is now $isBound")
}
}
Here's the BLEConnectionManager.unBindService()
fun unBindService(context: Context) {
// NOTE I've logged the service and connection here, they're non-null and BLE works fine in this Activity
if (serviceConnection != null && isBound) context.unbindService(serviceConnection)
}
So what have I missed, and what am I doing wrong that causes the exception?
I was calling unbind too many times (on a service that had previously unbound and hadn't been bound again since). This was because I had forgotten to set my BLEConnectionManager isBound flag in that class' unbind method. Whoops.
I am starting a foreground service using the following code
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent);
} else {
context.startService(intent);
}
This starts a foreground service. In Android Oreo and above, we must call startForeground() method within 5 seconds. Now in my service, we do some processing and if certain conditions are not met, then I don't call startForeground() method. Instead, I try to kill the service.
if (someConditionMet) {
startForeground(notificationId, notification)
} else {
stopSelf()
}
Now if someConditionMet variable is false, then my app crashes with the following crash log.
2019-04-10 16:57:25.695 19785-19785/com.awesomedroidapps.foregroundactivity E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.awesomedroidapps.foregroundactivity, PID: 19785
android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{e78d43f u0 com.awesomedroidapps.foregroundactivity/.ForegroundServiceTest}
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1835)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6863)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:537)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
I don't understand that when I am stopping the service then why is it necessary to call startForeground() method? Is there any way we can stop the foreground service without calling startForeground() method?
You can't. Period.
You can't stop a foreground service before the startForeground has been called and successfully executed. It is mandatory to finish this call before any action in the foreground service is taken.
No matter what combinations of stopSelf() and stopForeground() you use, it would not do what you desire to do.
Here is a really nice article about the same:
Foreground Service Pitfalls
If you want to stop service without creating actual notification you can just invoke startForeground with stub notification and cancel in right after stopSelf is invoked.
if (conditionMet)
startForeground(notificationId, notification)
} else {
startForeground(STUB_NOTIFICATION_ID, createStubNotification())
stopSelf()
cancelStubNotification()
}
private fun createStubNotification(): Notification {
val notificationManager =
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) {
notificationManager.createNotificationChannel(
NotificationChannel(
STUB_NOTIFICATION_CHANNEL_ID,
STUB_NOTIFICATION_CHANNEL_NAME,
IMPORTANCE_LOW
).apply { setShowBadge(false) }
)
}
return with(NotificationCompat.Builder(this, STUB_NOTIFICATION_CHANNEL_ID)) {
setBadgeIconType(NotificationCompat.BADGE_ICON_NONE)
setOngoing(true)
setSmallIcon(R.drawable.ic_notification)
priority = NotificationCompat.PRIORITY_LOW
setShowWhen(false)
setSilent(true)
build()
}.also { notificationManager.notify(STUB_NOTIFICATION_ID, it) }
}
private fun cancelStubNotification() =
(getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager)
.cancel(STUB_NOTIFICATION_ID)
Try this: Use a static variable and track the state of your service i.e running or not running, then check the state before calling stopself(). When the service is started, update the boolean flag to true and when it stops, update the boolean flag to false.
Since Android Oreo you cannot start a service when the app is not in foreground. In my app I start a service in the activity's onStart-method. This works perfectly fine most of the times. However, from time to time an IllegalStateException is thrown saying that the application is trying to start a service while in the background:
java.lang.IllegalStateException: Not allowed to start service Intent { act=ui cmp=com.someapp/.services.ConnectionService }: app is in background uid UidRecord{8d70361 u0a255 TPSL bg:+3m12s948ms idle change:cached procs:1 proclist:20368, seq(0,0,0)}
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1666)
at android.app.ContextImpl.startService(ContextImpl.java:1611)
at android.content.ContextWrapper.startService(ContextWrapper.java:677)
at com.someapp.ui.SomeActivity.connectToBackend(SomeActivity.java:62)
at com.someapp.ui.SomeActivity.onStart(SomeActivity.java:55)
at com.someapp.ui.MainActivity.onStart(MainActivity.kt:228)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1391)
at android.app.Activity.performStart(Activity.java:7348)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3131)
at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:180)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:165)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:142)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1947)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7032)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:964)
I start the service as follows:
#Override
protected void onStart() {
if (BuildConfig.DEBUG_MODE) Log.d(TAG, "activity started");
super.onStart();
connectToBackend();
}
void connectToBackend() {
Intent intent = new Intent(this, ConnectionService.class);
intent.setAction("ui");
startService(intent);
getApplicationContext().bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
I noticed that this only happens when I lock and then unlock the phone while in the app. I cannot reproduce it consistently.
Does somebody have the same issue?
The device I'm using is a Samsung Galaxy S10e.
For post Nougat devices, use startForegroundService, and for pre Oreo devices, use startService
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent);
} else {
startService(intent);
}
It's mine BroadcastReciever class. The class working on Boot phone status.
Code ;
public class BroadCastRecieverBoot extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent ıntent) {
if(Intent.ACTION_BOOT_COMPLETED.equals(ıntent.getAction()))
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(new Intent(context, MyService.class));
context.startForegroundService(new Intent(context, GPSTracker.class));
} else {
context.startService(new Intent(context, MyService.class));
context.startService(new Intent(context, GPSTracker.class));
}
}
}
}
I get This Error ;
android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1792)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6523)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:857)
It doesn't work on Android Oreo now. I don't know what is the mistake of that.
According to official document of Android 8.0 Background Execution Limits
Android 8.0 introduces the new method
startForegroundService() to start a new service in the foreground.
After the system has created the service, the app has five seconds to
call the service's startForeground() method to show the new service's
user-visible notification. If the app does not call startForeground()
within the time limit, the system stops the service and declares the
app to be ANR.
So, make sure you have started ongoing notification by calling startForeground (int id, Notification notification) in the onCreate() method of your service.
Note: Apps targeting API Build.VERSION_CODES.P or later must request the permission Manifest.permission.FOREGROUND_SERVICE in order to use this API.
Have been creating a custom notification, so far implemented it successfully getting the notification, however when i am trying to call a function/method from MainActivity using the button on the notification i created i get the below error :
System services not available to Activities before onCreate()
Below is the method defined by me inside the MainActivity that updates the notification UI and also stops the mediaplayer.
public void attachMediaActivity()
{
//INITIALIZE THE CONTEXT
context =this;
notificationManager=(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
remoteViews=new RemoteViews(this.getPackageName(),R.layout.custom_notification);
remoteViews.setImageViewResource(R.id.notif_icon,R.drawable.stream_icon);
remoteViews.setTextViewText(R.id.notif_title,"stopped");
Intent button_intent= new Intent("button_clicked");
button_intent.putExtra("id",notification_id);
Intent notification_intent=new Intent(context,MainActivity.class);
PendingIntent pendingIntent=PendingIntent.getActivity(context,0,notification_intent,PendingIntent.FLAG_UPDATE_CURRENT);
builder =new NotificationCompat.Builder(context);
builder.setSmallIcon(R.mipmap.ic_launcher)
.setCustomBigContentView(remoteViews)
.setContentIntent(pendingIntent)
.setOngoing(true);
notificationManager.notify(notification_id,builder.build());
if (mediaPlayer.isPlaying())
{
mediaPlayer.stop();
}
}
Broadcast listener attached to the button of notification that calls the above method from main activity.
public class Button_listener extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent)
{
NotificationManager manager =(NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancel(intent.getExtras().getInt("id"));
Toast.makeText(context, "GENERATED BY NOTIFICATION", Toast.LENGTH_SHORT).show();
new MainActivity().attachMediaActivity();
}
}
LOGCAT:
01-24 11:52:29.010 13062-13062/com.amplitude.tron.samplemediaplayer E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.amplitude.tron.samplemediaplayer, PID: 13062
java.lang.RuntimeException: Unable to start receiver com.amplitude.tron.samplemediaplayer.Button_listener: java.lang.IllegalStateException: System services not available to Activities before onCreate()
at android.app.ActivityThread.handleReceiver(ActivityThread.java:2750)
at android.app.ActivityThread.access$1800(ActivityThread.java:157)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1433)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5525)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:730)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)
Caused by: java.lang.IllegalStateException: System services not available to Activities before onCreate()
at android.app.Activity.getSystemService(Activity.java:5288)
at com.amplitude.tron.samplemediaplayer.MainActivity.attachMediaActivity(MainActivity.java:159)
at com.amplitude.tron.samplemediaplayer.Button_listener.onReceive(Button_listener.java:21)
at android.app.ActivityThread.handleReceiver(ActivityThread.java:2743)
at android.app.ActivityThread.access$1800(ActivityThread.java:157)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1433)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5525)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:730)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)
What i have implemeted so far :
where am i going wrong .. also prior to calling notification manager i have been getting getPackageName() as NULL
Please help! Thanks in advance
new MainActivity().attachMediaActivity();
Problem lies here. Contrary of normal way, creating an instance of Activity with a new tag won't let you go through with its lifecycle that it supposed to.
You can launch your Activity by setting up a bundle, pass it with Intent, initiate a startActivity and finally check the bundle value in Activity and invoke the attachMediaActivity method. Or else, if you want, you can get a hold of your current Activity instance in these ways and call the method.
The error that you got clearly says, System services not available to Activities before onCreate().
That is, You can not use NotificationManager from an Activity without calling startActivity(Intent).
What you can do is, start the activity with intent+ extras to call the method inside the MainActivity. OR you can use the CallBack method using Interfaces.
Update
Declare Intent as:
Intent intent = new Intent(context, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("attachMedia",true); // Extra info
context.startActivity(intent);
And now, inside the MainActivity onCreate(), (after all initialization)
boolean attachMedia = getIntent().getBooleanExtra("attachMedia",false);
if (attachMedia) {
attachMediaActivity();
}