我收到以下错误:
suspend function 'getInfo' should be called only from a coroutine or another suspend function
你能告诉我我做错了什么吗?
import android.appwidget.AppWidgetManager
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.util.Log
import com.myapp.test.WakeLocker.acquire
import com.myapp.test.WakeLocker.release
import org.json.JSONObject
import java.util.concurrent.ExecutionException
class WidgetService : BroadcastReceiver() {
var json = JSONObject()
override fun onReceive(context: Context, intent: Intent) {
//wake the device
acquire(context)
//increase the number in the widget
val preferences = context.getSharedPreferences("PREFS", 0)
val urlCode = preferences.getString("urlCode", "")
Log.d("WidgetService1", urlCode!!)
if (urlCode != "") {
val getPack = GetPack(urlCode)
json = try {
getPack.getInfo()
} catch (e: ExecutionException) {
throw RuntimeException(e)
} catch (e: InterruptedException) {
throw RuntimeException(e)
}
val editor = preferences.edit()
editor.putString("json", json.toString())
editor.apply()
}
//force widget update
val widgetIntent = Intent(context, MyWidget::class.java)
widgetIntent.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
val ids = AppWidgetManager.getInstance(context)
.getAppWidgetIds(ComponentName(context, MyWidget::class.java))
widgetIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
context.sendBroadcast(widgetIntent)
Log.d("WidgetService", "Widget set to update!")
//go back to sleep
release()
}
}
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.json.JSONArray
import org.json.JSONObject
import org.jsoup.Jsoup
import java.io.IOException
class GetPack(id: String) {
private val baseURL = "http://192.xxx.xxx.xxx"
private val finalURL = "$baseURL:8080"
suspend fun getInfo(): JSONObject = withContext(Dispatchers.IO) {
val json = JSONObject()
try {
val document = Jsoup.connect(finalURL).get()
val steps = JSONArray()
val elements = document.select("#progressTracker-container > div")
for (ele in elements) {
val item = JSONObject()
val reached = ele.attr("data-reached") == "reached"
val message = ele.select(".milestone-primaryMessage").first().ownText()
val data = ele.select(".milestone-primaryMessage > .nowrap").text()
item.put("reached", reached)
item.put("message", message)
item.put("data", data)
steps.put(item)
}
val primaryStatus = document.getElementById("primaryStatus")
json.put("status", primaryStatus.text())
json.put("steps", steps)
} catch (e: IOException) {
e.printStackTrace()
} catch (e: Exception) {
throw RuntimeException(e)
}
json
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation 'org.jsoup:jsoup:1.11.2'
}
suspend fun getInfo()
班级的 GetPack
被提及为 suspend
。在 Kotlin 中,挂起函数应该从挂起函数或协程中调用。
关于协程的更多信息:https://developer.android.com/kotlin/coroutines/coroutines-adv
答案:
您可以执行以下任一操作来解决此错误:
suspend
中删除getInfo()
并使其变得简单fun getInfo()
。但我的建议是不要这样做,因为我们在这里进行 Json 解析,这可能需要时间。WidgetService
类中,您可以使用 IO 调度程序启动协程,如下所示:1. Add implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.0' in app build gradle.
2. Use lifecycleScope.launch(Dispatchers.IO) {} as follow
lifecycleScope.launch(Dispatchers.IO) {
val getPack = GetPack(urlCode)
json = try {
getPack.getInfo()
} catch (e: ExecutionException) {
throw RuntimeException(e)
} catch (e: InterruptedException) {
throw RuntimeException(e)
}
val editor = preferences.edit()
editor.putString("json", json.toString())
editor.apply()
}