【问题标题】:Kotlin coroutine does half the task instead of completing the taskKotlin 协程做了一半的任务而不是完成任务
【发布时间】:2022-01-10 06:16:24
【问题描述】:

我有一个功能可以在按下按钮时将数据保存到 CSV。

private fun saveDataToCSV() {
        val CSV_HEADER = "activity,exerciseType,set #,reps,weights,date,dateDate,notes"
        var baseDir = android.os.Environment.getExternalStorageDirectory().toString() + "/Download"
        var fileName = "activities.csv"
        var fileWriter = File(baseDir,fileName)
        try {
            Toast.makeText(this,"Saving to CSV ...",Toast.LENGTH_SHORT).show() //Not showing for some reason

            GlobalScope.launch {
                fileWriter.delete()
                fileWriter.createNewFile()
                fileWriter.appendText(CSV_HEADER)
                fileWriter.appendText("\n")

                for (activity in queryObjectInRealm()) {
                    fileWriter.appendText(activity.activity)
                    fileWriter.appendText(",")
                    fileWriter.appendText(activity.exerciseType)
                    fileWriter.appendText(",")
                    fileWriter.appendText(activity.sets.toString())
                    fileWriter.appendText(",")
                    fileWriter.appendText(activity.reps.toString())
                    fileWriter.appendText(",")
                    fileWriter.appendText(activity.weights.toString())
                    fileWriter.appendText(",")
                    fileWriter.appendText(activity.date.toString())
                    fileWriter.appendText(",")
                    fileWriter.appendText(activity.dateDate.toString())
                    fileWriter.appendText(",")
                    fileWriter.appendText(activity.notes!!)
                    fileWriter.appendText("\n")
                }
            }
            Toast.makeText(this,"CSV saved to Downloads",Toast.LENGTH_SHORT).show()
        } catch (e: Exception) {
            Toast.makeText(this,"Unable to save locally",Toast.LENGTH_SHORT).show()
            e.printStackTrace()
        }
    }

我最初遇到的问题是 Toast Saving to CSV ... 没有出现。事实上,在 CSV 完成写入之前,UI 会一直挂起。根据我所看到的 (The application may be doing too much work on its main thread),我认为我应该将 CSV 写入任务移至不同的线程。

所以我在协程的帮助下做到了。我是协程的新手,从我所看到的情况来看,我认为我的实现方式是正确的.. 还是不正确?

使用上面的代码,Toast Saving to CSV ... 现在出现了,但 CSV 缺少很多数据,我不知道为什么。我错过了什么?谢谢。

【问题讨论】:

  • 您如何/何时检查 CSV 文件中的数据?
  • 当我看到 toast CSV saved to Downloads 时,我会去我手机下载目录中的 CSV 文件查看它
  • CSV saved to Downloads 会立即打印出来,launch 是异步的,所以在打印该行之前,您不必等待它在这里完成
  • 嗯,这是否意味着我应该将CSV saved to Downloads 放在GlobalScrope.launch 的末尾?
  • 我认为你应该以不同的方式重新设计函数,因为即使捕获异常也无法像这样解决launch。你可能应该让你的函数暂停。

标签: kotlin coroutine


【解决方案1】:

所以我在协程的帮助下做到了。我是协程的新手,从我所看到的情况来看,我认为我的实现方式是正确的.. 还是不正确?

这里有几个问题:

  • 不鼓励使用GlobalScope,因为它不会自动处理您的协同程序的取消(如果不手动控制它们可以永远存在)
  • 因为您使用的是GlobalScope 而不是等待启动的作业,所以您无法真正知道您的协程何时完成了文件的写入。最后的"CSV saved to Downloads" 在启动协程后立即打印,而不是在协程完成时打印

最好让函数自己挂起,通过切换上下文来处理IO:

private suspend fun saveDataToCSV() {
        val CSV_HEADER = "activity,exerciseType,set #,reps,weights,date,dateDate,notes"
        var baseDir = android.os.Environment.getExternalStorageDirectory().toString() + "/Download"
        var fileName = "activities.csv"
        var fileWriter = File(baseDir,fileName)
        try {
            Toast.makeText(this,"Saving to CSV ...",Toast.LENGTH_SHORT).show() //Not showing for some reason

            withContext(Dispatchers.IO) {
                fileWriter.delete()
                fileWriter.createNewFile()
                fileWriter.appendText(CSV_HEADER)
                fileWriter.appendText("\n")

                for (activity in queryObjectInRealm()) {
                    fileWriter.appendText(activity.activity)
                    fileWriter.appendText(",")
                    fileWriter.appendText(activity.exerciseType)
                    fileWriter.appendText(",")
                    fileWriter.appendText(activity.sets.toString())
                    fileWriter.appendText(",")
                    fileWriter.appendText(activity.reps.toString())
                    fileWriter.appendText(",")
                    fileWriter.appendText(activity.weights.toString())
                    fileWriter.appendText(",")
                    fileWriter.appendText(activity.date.toString())
                    fileWriter.appendText(",")
                    fileWriter.appendText(activity.dateDate.toString())
                    fileWriter.appendText(",")
                    fileWriter.appendText(activity.notes!!)
                    fileWriter.appendText("\n")
                }
            }
            Toast.makeText(this,"CSV saved to Downloads",Toast.LENGTH_SHORT).show()
        } catch (e: Exception) {
            Toast.makeText(this,"Unable to save locally",Toast.LENGTH_SHORT).show()
            e.printStackTrace()
        }
    }
}

还要注意,重复使用appendText 效率非常低,因为您每次都会创建和关闭一个新的输出流。最好只创建一次输出流并将所有内容写入其中:

val file = File(baseDir,fileName)

file.bufferedWriter().use { writer -> 
    // use writer.append("...") repeatedly
} // automatically closed at the end of the use{} block

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-07-19
    • 1970-01-01
    • 2015-08-10
    • 1970-01-01
    • 1970-01-01
    • 2022-10-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多