Long running background task from BroadcastReceiver - which class to use? - android

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

Related

Unable to start service lateinit property has not been initialized

Hi and thank you for your expertise.
I am trying to run a service which is going to display a notification and after some time check if it is still there or user has got rid of it.
So in the MainActivity.kt when onPause function is triggered I start the service like this
startService(Intent(this,NewService::class.java))
then in the NewService.kt I would like to check using MainActivity.kt function checkNotifications() if there is a notification displayed
class NewService:Service() {
#RequiresApi(Build.VERSION_CODES.M)
override fun onStartCommand(init : Intent, flag : Int, startId: Int):Int{
MainActivity().checkNotifications()
return START_STICKY
}
override fun onDestroy() {
super.onDestroy()
}
override fun onBind(p0: Intent?): IBinder? {
return null
}
}
This is what checkNotifications() function in MainActivity.kt looks like
#RequiresApi(Build.VERSION_CODES.M)
fun checkNotifications(){
val notifications: Array<StatusBarNotification> = notificationManager.activeNotifications
if(notifications.isNotEmpty())
{
println("Notification exists")
}
else
{
println("No notifications")
}
}
So my app works 'fine' as long as I don't call checkNotifications(). What I mean the service starts and so on. However when I try to call checkNotifications() I get this error
java.lang.RuntimeException: Unable to start service abc.com.app.NewService#b380e9f with Intent { cmp=abc.com.app/.NewService }: kotlin.UninitializedPropertyAccessException: lateinit property notificationManager has not been initialized
The property notificationManager is initialized in onCreate() function and everyting is working up until I call checkNotifications()
Would anyone be so kind and tell me what am I doing wrong?
Thank You
MainActivity().checkNotifications()
Never create an instance of an activity yourself. Move checkNotifications() into the service or into some utility class (where you provide a Context as a parameter to checkNotifications() for the purposes of obtaining a NotificationManager).

Foreground service is getting killed outside without calling selfStop?

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

Triggering Notification from service when app is in background / killed

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.

Foreground Service Stopself after hours working

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

BroadcastReceiver not getting updated from ACTION_BATTERY_CHANGED

I've created custom broadcast receiver to listen for battery changes (I would like to monitor the percentage level of the battery)
However I'm not getting any updates. Here is my setup:
class MyService : IntentService("MyService") {
val receiver: PowerConnectionReceiver = PowerConnectionReceiver()
override fun onHandleIntent(intent: Intent?) {
Timber.d("Service started now")
}
override fun onCreate() {
val batteryStatus: Intent? =
IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { ifilter ->
registerReceiver(receiver, ifilter)
}
}
class PowerConnectionReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val status: Int = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1)
Timber.d("Battery changed")
}
}
}
You will receive updates for the < 1 millisecond time that your IntentService is running. Your IntentService shuts down as soon as onHandleIntent() returns. IntentService is designed for short-term transactional sorts of work, not long-term operation.
Switch to a regular Service. Make sure that it is a foreground service (using startForeground()), as otherwise it will only run for 1 minute on Android 8.0+.

Categories

Resources