在kotlin协程中取消后如何重新启动作业?

Mah*_*iya 8 kotlin kotlin-coroutines

job取消后如何重新启动kotlin coroutines

我有 2 个按钮,1 个用于启动协程,另一个用于取消作业。但是在我取消作业后,协程不会再次启动。

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
    }

}
Run Code Online (Sandbox Code Playgroud)

Mar*_*nik 6

您不恰当地使用链接到片段生命周期的顶级作业作为按需取消协程的手段。

替换此样板:

class TestFragment : Fragment(), CoroutineScope {

    private lateinit var job: Job
    override val coroutineContext: CoroutineContext
        get() = Dispatchers.Main + job
Run Code Online (Sandbox Code Playgroud)

有了这个:

class TestFragment : Fragment(), CoroutineScope by MainScope {
    override fun onDestroy() {
        cancel()
    }
Run Code Online (Sandbox Code Playgroud)

这将自动解决您引入的问题之一:它使用 aSupervisorJob而不是普通的Job.

接下来,您需要访问您在其中启动的作业onClick:

    private var button1Job: Job?

    ...

    button1.setOnClickListener {
        button1Job = launch {
           ...
           button1Job = null
        }
Run Code Online (Sandbox Code Playgroud)

您现在可以在button2侦听器中取消此作业:

    button1Job?.cancel()
Run Code Online (Sandbox Code Playgroud)


Seg*_*aab 6

除了上面的答案,你应该使用

 button1Job.cancelChildren()
Run Code Online (Sandbox Code Playgroud)

这保留了作业的完整性,并确保它可以在取消后重新启动,不像取消会影响作业的状态