将值写入 Google Sheet - 协程和 NetworkOnMainThreadException 问题

问题描述 投票:0回答:1

我正在尝试将列表中的数据写入特定的 Google 表格。我已经设置了配置,但遇到了一个似乎与不使用协程相关的错误。

我的做法正确吗?有没有办法在没有协程的情况下实现这一点,因为我不确定如何实现它们?如果需要协程,如何正确集成它们?

触发设备上的按钮时发生错误,导致应用程序关闭:

FATAL EXCEPTION: main
Process: com.nase.naseapp, PID: 26027
android.os.NetworkOnMainThreadException
...
...
...
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
    Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [androidx.compose.ui.platform.MotionDurationScaleImpl@13df640, androidx.compose.runtime.BroadcastFrameClock@de98979, StandaloneCoroutine{Cancelling}@e896be, AndroidUiDispatcher@5ea431f]

有问题的类包含按钮的

onClick
函数调用的方法:

class SheetsAPI(private val application: Application, credential: GoogleCredential) {
    private val jsonFactory = JacksonFactory.getDefaultInstance()
    private val httpTransport = NetHttpTransport()
    private val service: Sheets = Sheets.Builder(httpTransport, jsonFactory, credential)
        .setApplicationName(application.getString(R.string.app_name))
        .build()

    fun submitExpensesToGoogleSheet(expenses: List<ExpenseData>){
        val spreadsheetId = "_____spreadsheetid____"
        val range = "Sheet1!A1:B2"
        val valueRange = ValueRange().setValues(
            listOf(
                listOf("Expense", "Amount"),
                *expenses.map { listOf(it.title, it.amount) }.toTypedArray()
            )
        )

        service.spreadsheets().values().update(spreadsheetId, range, valueRange)
            .setValueInputOption("RAW")
            .execute()

        println("Sending data to Sheet")
    }
}

任何关于为什么会发生

NetworkOnMainThreadException
的见解以及关于实现协程或替代方案的指导将受到高度赞赏。谢谢!

android kotlin android-asynctask google-sheets-api kotlin-coroutines
1个回答
0
投票

正如您所说并分享的那样,您收到了 NetworkOnMainThreadException。在以下情况下抛出此异常:

“...应用程序尝试在其上执行网络操作 主线程。” 参考

您之所以会遇到此异常,是因为您在以下几行中的逻辑:

service.spreadsheets().values().update(spreadsheetId, range, valueRange)
            .setValueInputOption("RAW")
            .execute()

上面的调用是执行网络请求的调用,您不能在主线程上执行这些请求,因为它们:

  1. 抓紧时间
  2. 阻塞主线程

为了克服这个问题,可以使用协程来处理网络请求结果的调用和获取。您还可以使用其他组件。

如何将逻辑包装在协程中的示例如下:

suspend fun submitExpensesToGoogleSheet(expenses: List<ExpenseData>) {
        val spreadsheetId = "_____spreadsheetid____"
        val range = "Sheet1!A1:B2"
        val valueRange = ValueRange().setValues(
            listOf(
                listOf("Expense", "Amount"),
                *expenses.map { listOf(it.title, it.amount) }.toTypedArray()
            )
        )

        withContext(Dispatchers.IO) {
            
           service.spreadsheets().values().update(spreadsheetId, range, valueRange)
            .setValueInputOption("RAW")
            .execute()

        println("Sending data to Sheet")

       }
    }
  }

请注意,您需要将您的方法设为挂起方法,并从另一个挂起方法或协程内部调用该方法。 您可以在此处阅读有关协程的更多信息。

© www.soinside.com 2019 - 2024. All rights reserved.