单击按钮禁用服务重新启动 [英] Disable service restart on button click

查看:59
本文介绍了单击按钮禁用服务重新启动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我启动了一个前台服务,当用户单击按钮时,该服务会下载文件.现在发生的是,当我再次单击该按钮时,服务内的线程第二次启动,并且在通知中看到两个线程的进度都已更新(在线程之间跳过presentae).

如果第一个线程正在运行,如何防止启动第二个线程?如果服务仍在运行,如何防止调用startService()onStartCommand()?

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)
        }
    }
}

通话

buttonGoNext.setOnClickListener {
    val intent = Intent(this, DownloadActivity::class.java)
    startActivity(intent)
}

解决方案

在您的startService函数中,您要检查此服务是否已在运行.如果该服务已经在运行,则可以提早返回.有多个唯一的OneTimeWorkRequest ,它也可以解决该问题. /p>

此外,您应该更好地将代码中的职责分开.当前,您的ForegroundService类可以同时处理太多事情.您创建了通知渠道,显示了通知,并且可能还想照顾您描述的行为.通常,将这些关注点分离出来并将其移到不同的类中是一种很好的做法.这也使其更具可测试性.

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)
}

解决方案

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.

这篇关于单击按钮禁用服务重新启动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆