I did a Foreground Service using Kotlin. It's works , but after seven hours running my service stop and my app returned to its first page (login page). But the only method to stop my service is executed when I click in a "stop service" button, so why my service is stopping after 7 hours if i didn't press any button? i'm using a moto g7, android 9.0
class RastreioService : Service() {
companion object {
var serviceAtivado = false //service activated
}
override fun onBind(intent: Intent?): IBinder? {
TODO("Not yet implemented")
}
override fun onCreate() {
super.onCreate()
serviceAtivado = true
val notificationIntent = Intent(this, RastreioService::class.java)
val pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
val notification = Notification.Builder(this, "1")
.setSmallIcon(R.drawable.ic_gps_ativo)
.setContentTitle("Localização Sendo Acessada")
.setContentText("A sua localização está sendo acessada")
.setContentIntent(pendingIntent)
.build()
startForeground(1, notification)
/*request location methods*/
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return START_NOT_STICKY
}
override fun onDestroy() {
serviceAtivado = false
super.onDestroy()
this.gerenciadorDeLocalizacao.DesativarBuscaPorLocalizaca()
}
}
OS still can shut down services if it feels like it needs to, but it can be resumed afterward.
on onStartCommand you are returning START_NOT_STICKY
you can use which does not re start the service.
You can use START_REDELIVER_INTENT to save progress of your service and re start it from where it left of.
Link to the docs
A foreground service can still be killed by the OS, you have no guarantees that the service will last forever. A foreground service just makes it less likely to be killed
Related
Since AsyncTask, IntentSerrvice and JobIntentService are all deprecated, which tool or class should I go for in 2022?
I want to re-schedule alarms in a BroadcastReceiver after a device rebooted (since alarms get lost in the process). The task will most probably take < 1 min to finish. I just need the safety of it completing and not being killed off by the system.
The documentation on Broadcasts shows an (outdated) example with goAsync() and the deprecated AsyncTask.
But it also mentions JobService. Is that the replacement? What about WorkManager?
goAsync() return a PendingIntent - it mean you ask for android system extend time life of Broadcast receiver => goAsync() is used for short background task.
Life time of BroadcastReceiver is very short, so... for long time background task, you must to change to other context has longer life time, such as: Service, JobService..etc.
Example:
BroadcastReceiver received intent
BroadcastReceiver start a service, run worker thread to process long time task
after worker thread finish, call finish service too
=========================================
class MyIntentService : Service() {
private val handleThread = HandlerThread("MyThread")
private lateinit var workerHandler: Handler
override fun onCreate() {
super.onCreate()
handleThread.start()
workerHandler = Handler(handleThread.looper)
}
override fun onDestroy() {
workerHandler.removeCallbacksAndMessages(null)
handleThread.quitSafely()
super.onDestroy()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val data = intent?.data
workerTask(data)
return START_NOT_STICKY
}
private fun workerTask(data: Uri?) {
workerHandler.post {
heavyTask(data)
finishMyIntentService()
}
}
private fun finishMyIntentService() {
stopSelf()
}
private fun heavyTask(data: Uri?) {
// to do heavyTask example
for (i in 1..20)
{
Log.d("test","#heavyTask() $i")
Thread.sleep(1000)
}
}
override fun onBind(intent: Intent?): IBinder? {
TODO("Not yet implemented")
}
}
then startService from BroadCastReceiver
I am working on scheduling app in which i have to run the app until it completes it process
but the problem is , Process is getting killed after few minute even it is running on foreground service ...
class MyService : Service(){
#RequiresApi(Build.VERSION_CODES.O)
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
showNotification()
println("intent ${startId}")
isServiceStarted =true
val action = intent?.action
when(action){
ADD_SERVICE ->{
val sms = intent.getParcelableExtra<Sms>(Add_kEY)
if(sms!=null) {
schedule(sms) } }
DELETE_SERVICE ->{ }
}
return START_REDELIVER_INTENT
}
}
// Manifest file
<service android:name=".service.MyService "
android:foregroundServiceType="dataSync"
/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
you should call startForeground() in your service to attach your service to your application lifecycle to prevent OS from killing your service.
foreground-services
AlarmService.kt
class AlarmService : Service() {
private var vibrator: Vibrator? = null
override fun onCreate() {
super.onCreate()
vibrator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val vibratorManager = this.getSystemService(Context.VIBRATOR_MANAGER_SERVICE) as VibratorManager
vibratorManager.defaultVibrator
} else {
#Suppress("DEPRECATION")
getSystemService(VIBRATOR_SERVICE) as Vibrator
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int):
Int {
val pattern = longArrayOf(1500, 800, 800, 800)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
vibrator?.vibrate(VibrationEffect.createWaveform(pattern, 0))
} else {
#Suppress("DEPRECATION")
vibrator?.vibrate(pattern, 0)
}
}
override fun onDestroy() {
super.onDestroy()
vibrator?.cancel() // ---< This is not called
Log.e("served", "Service Stopped") // ---< This is called and shows in logcat
}
}
In My BroadcastRecciever,
private fun snoozeAlarm(context: Context?, intent: Intent?){
val intentService = Intent(context.applicationContext,
AlarmService::class.java)
context.applicationContext.stopService(intentService)
}
As you can see, vibrator?.cancel() is not called when I tried to stop the service class from broadcastReciever.
The notification in my service is cleared but phone keeps vibrating.
Tested with emulator (pixel 2) api 31
UPDATE
It appears, this is only an issue with android studio emulator using bumblebee
When I ran with a real device, it worked.
Try swapping the order of the operations in Your onDestroy method. Most importantly put the super call at the end of the method:
override fun onDestroy() {
vibrator?.cancel()
Log.e("served", "Service Stopped")
super.onDestroy()
}
Freeing up resources and uninitializing any child classes probably should be done on a fully functional object and since Your service was previously in the destruction process already (because of calling super.onDestroy() before your own operations) it might have had some impact on the vibrator?.cancel() code completion.
I'm making a todolist app where the user needs to add a task along with date and time that i use later to trigger the notification , when app is in foreground , it works fine but since services are submitted to limitations after android oreo , now i'm lost on how to trigger the notification when app is in background or killed , if you guys could enlighten me , i woudl appreciate it
This is my service class
class NotificationService(var context: FragmentActivity) : Service(){
private lateinit var remindersViewModel: remindersViewModel
private lateinit var compat : NotificationManagerCompat
override fun onCreate() {
super.onCreate()
compat = NotificationManagerCompat.from(this)
remindersViewModel = ViewModelProvider(context)[remindersViewModel::class.java]
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
isNotificationEnabled()
return START_NOT_STICKY
}
override fun onDestroy() {
super.onDestroy()
}
private fun isNotificationEnabled(){
//TODO : NOTIFICATION
val notificationPrefs = getSharedPreferences("notificationPrefs", Context.MODE_PRIVATE)
val isNotificationEnabled = notificationPrefs.getBoolean("notification", false)
remindersViewModel.getAllTasks().observe(context, Observer {
if(isNotificationEnabled){
CoroutineScope(Dispatchers.Main).launch {
delay(3000)
HandleOperations.taskNotification(it, context, compat)
}
}
})
}
}
As of Android Oreo, all background services will be killed if not visible by a foreground service. The best case scenario for your problem is to use a Job Scheduler (here).
For timely event based tasks Job Sceduler is the only options though it's no longer available in the support library.
You will also need a Notification Channel for devices with Oreo and above.
I've been browsing many topics about resuming an activity from a foreground service without finding any concrete answer to my problem.
I'm trying to put a foreground service in my app, and I want the app to be resumed when clicking on the service notification instead of relaunching it. I've tried using the getLaunchIntentForPackage() method from PackageManager, which is the closest to what I want to do.
However, the activity's onCreate is still being called when resuming the app by clicking on the notification.
So here is my question, how to resume an app from a notification's content intent?
I'm starting my ForegroundService in the activity's onStop so it gets called when the app is killed or sent to background.
override fun onStop() {
super.onStop()
Log.v(TAG, "onStop")
ForegroundService.startService(this, "Hellooooooo, here is the background")
}
ForegroundService
class ForegroundService: Service() {
companion object {
private const val CHANNEL_ID = "ForegroundServiceChannel"
fun startService(context: Context, message: String) {
val startIntent = Intent(context, ForegroundService::class.java)
startIntent.putExtra("inputExtra", message)
ContextCompat.startForegroundService(context, startIntent)
}
fun stopService(context: Context) {
val stopIntent = Intent(context, ForegroundService::class.java)
context.stopService(stopIntent)
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val input = intent!!.getStringExtra("inputExtra")
val launchIntent = packageManager.getLaunchIntentForPackage(APP_PACKAGE)
val contentIntent = PendingIntent.getActivity(applicationContext, 0,
launchIntent, 0)
val notification: Notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Foreground Service")
.setContentText(input)
.setContentIntent(contentIntent)
.setSmallIcon(R.drawable.ic_call_to_action)
.setOngoing(true)
.build()
startForeground(1, notification)
createNotificationChannel()
return START_NOT_STICKY
}
override fun onBind(p0: Intent?): IBinder? {
return null
}
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val serviceChannel = NotificationChannel(
CHANNEL_ID,
"Foreground Service Channel",
NotificationManager.IMPORTANCE_DEFAULT
)
val manager = getSystemService(
NotificationManager::class.java
)
manager?.createNotificationChannel(serviceChannel)
}
}
}
Try set in the manifest for activity android:launchMode="singleInstance".
Do not forget set some your action to your activity intent:
activityIntent.setAction(ACTION_STARTED_FROM_NOTIFICATION);
Override onNewIntent in the activity.
in onCreate and in onNewIntent do check
if(ACTION_STARTED_FROM_NOTIFICATION.equalsIgnoreCase(intent.getAction()))
{ do what you need }