【问题标题】:How to restart job after cancel in kotlin coroutines?如何在kotlin协程中取消后重新启动作业?
【发布时间】:2020-01-07 12:43:22
【问题描述】:

kotlin coroutines中取消后如何重启job

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

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
    }

}

【问题讨论】:

  • 如果你决定不使用 MainScope(你应该使用它),去掉“get() = Dispatchers.Main + job”。这将在您每次访问时为您提供一个新的 CoroutineContext。

标签: kotlin kotlin-coroutines


【解决方案1】:

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

替换这个样板:

class TestFragment : Fragment(), CoroutineScope {

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

用这个:

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

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

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

    private var button1Job: Job?

    ...

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

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

    button1Job?.cancel()

【讨论】:

  • 为什么是button1Job = null
  • @MurilloComino 很晚了,但是......可能会在完成后释放对作业的引用,以便 GC 回收它。
【解决方案2】:

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

 button1Job.cancelChildren()

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-07
    • 1970-01-01
    • 1970-01-01
    • 2021-05-01
    • 2020-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多