Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to restart job after cancel in kotlin coroutines?

How to restart job after canceling in kotlin coroutines

I have 2 buttons, 1 to start coroutine and another to cancel the job. But after I cancel the job, coroutine not starts again.

class TestFragment : Fragment(), CoroutineScope {

    private lateinit var job: Job
    override val coroutineContext: CoroutineContext
        get() = Dispatchers.Main + job

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        binding = SettingFragmentBinding.inflate(inflater, container, false)

        job = Job()

        button1.setOnClickListener {
            launch {
                val currentTime = LocalDateTime.now()
                println(currentTime)
            }
        }

        button2.setOnClickListener {
            job.cancel()
        }

        return binding.root
    }

}
like image 669
Mahesh Babariya Avatar asked Jan 07 '20 12:01

Mahesh Babariya


2 Answers

In addition to the above answer, you should use

 button1Job.cancelChildren()

This retains the integrity of the job and ensures it can be relaunched after cancellation unlike cancel which affects the state of the job

like image 74
Oluwasegun Wahaab Avatar answered Oct 03 '22 19:10

Oluwasegun Wahaab


You're inappropriately using the top-level job linked to the lifecycle of the fragment as the means to cancel your coroutine on demand.

Replace this boilerplate:

class TestFragment : Fragment(), CoroutineScope {

    private lateinit var job: Job
    override val coroutineContext: CoroutineContext
        get() = Dispatchers.Main + job

with this:

class TestFragment : Fragment(), CoroutineScope by MainScope {
    override fun onDestroy() {
        cancel()
    }

This will automatically fix one of the problems you introduced: it uses a SupervisorJob instead of a plain Job.

Next, you need access to the job you launched in onClick:

    private var button1Job: Job?

    ...

    button1.setOnClickListener {
        button1Job = launch {
           ...
           button1Job = null
        }

You can now cancel this job in button2 listener:

    button1Job?.cancel()
like image 27
Marko Topolnik Avatar answered Oct 03 '22 20:10

Marko Topolnik