0

I start a foreground service that downloads a file when users click on a button. What happens now is when I click again on the button, the thread inside service starts second time and I see in a notification that progress is updated for both threads (jumps presentae between threads).

How can I prevent starting the second thread in case the first one is running, how can I prevent startService() or onStartCommand() is being called if the service is still running?

class ForegroundService : Service() {
    private val CHANNEL_ID = "ForegroundService Kotlin"

    companion object {

        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")
        createNotificationChannel()
        val notificationIntent = Intent(this, MainActivity::class.java)
        val pendingIntent = PendingIntent.getActivity(
            this,
            0, notificationIntent, 0
        )

        //start doing some work and update the notification
        //when done calling stopSelf();

        val notification = NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentTitle("Foreground Service Kotlin Example")
            .setContentText(input)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentIntent(pendingIntent)
            .build()

        startForeground(1, notification)

        return START_NOT_STICKY
    }

    override fun onBind(intent: 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)
        }
    }
}

Calling

buttonGoNext.setOnClickListener {
    val intent = Intent(this, DownloadActivity::class.java)
    startActivity(intent)
}
Son Truong
  • 13,661
  • 5
  • 32
  • 58
Dim
  • 4,527
  • 15
  • 80
  • 139
  • save the notification channel locally id and check it if there is already running notification with that id , just remove it or do not start new task – Quick learner Dec 07 '20 at 11:24

1 Answers1

0

In your startService function you want to check if this service is already running. If the service is already running, you could just early return. There is multiple SO threads already regarding the problem of how to find out if a service is already running.

To have a little more control over your background work, I would suggest you familiarize yourself with Android's WorkManager. You could create a unique OneTimeWorkRequest with a KEEP policy, that would solve the problem as well.

Also, you should seperate your responsibilities in your code a little better. Your ForegroundService class currently takes care of too many things at once. You create notification channels, show notifications and probably also want to take care of the behaviour you described. It is generally good practice to seperate those concerns and move them to different classes. This also makes it more testable.

j0h1_r
  • 61
  • 5