尽管使用异步,为什么我仍然会收到NetworkOnMainThreadException?

时间:2019-08-20 05:36:15

标签: android asynchronous kotlin coroutine kotlin-coroutines

这是我的程序,用于显示我在Android设备上制作的Web应用(数据产品)的结果。

package studio.nyaa.crimeprediction

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import java.net.URL
import android.util.Log
import android.widget.TextView
import com.beust.klaxon.JsonObject
import com.beust.klaxon.Parser
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.async

suspend fun obtainJson():JsonObject {
    val sourceURL = "http://yingzhou474.pythonanywhere.com/api"
    val jsonRes: String = URL(sourceURL).readText()
    val parser: Parser = Parser.default()
    val json = parser.parse(jsonRes) as JsonObject
    Log.d("oj", "oj finished")
    return json
}
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        runBlocking {
            val json = async{obtainJson()}.await()
            Log.d("postcoroutine", json.toString())
            val crime1: Double? = json.obj("data")?.double("AGGRAVATED ASSAULT")
            val crime2: Double? = json.obj("data")?.double("AUTO THEFT")
            val crime3: Double? = json.obj("data")?.double("COMMERCIAL BURGLARY")
            val crime4: Double? = json.obj("data")?.double("HOMICIDE")
            val crime5: Double? = json.obj("data")?.double("LARCENY")
            val crime6: Double? = json.obj("data")?.double("OTHER BURGLARY")
          val crime7: Double? = json.obj("data")?.double("RESIDENTIAL BURGLARY")
          val crime8: Double? = json.obj("data")?.double("ROBBERY")
            val year: Int? = json.int("year")
            val month: Int? = json.int("month")
            val day: Int? = json.int("day")
            val textView1: TextView = findViewById(R.id.editText1B)
            textView1.text = crime1?.toString() ?: "N/A"
            val textView2: TextView = findViewById(R.id.editText2B)
            textView2.text = crime2?.toString() ?: "N/A"
            val textView3: TextView = findViewById(R.id.editText3B)
            textView3.text = crime3?.toString() ?: "N/A"
            val textView4: TextView = findViewById(R.id.editText4B)
            textView4.text = crime4?.toString() ?: "N/A"
            val textView5: TextView = findViewById(R.id.editText5B)
            textView5.text = crime5?.toString() ?: "N/A"
            val textView6: TextView = findViewById(R.id.editText6B)
            textView6.text = crime6?.toString() ?: "N/A"
            val textView7: TextView = findViewById(R.id.editText7B)
            textView7.text = crime7?.toString() ?: "N/A"
            val textView8: TextView = findViewById(R.id.editText8B)
            textView8.text = crime8?.toString() ?: "N/A"
            val textViewDate: TextView = findViewById(R.id.editTextDate)
            textViewDate.text = "Date: $month/$day/$year"
        }
    }
}

这里的数据源是this site,它返回这种JsonObject:

{"data": {"AGGRAVATED ASSAULT": 6.87, "AUTO THEFT": 4.4, "COMMERCIAL BURGLARY": 1.3, "HOMICIDE": 0.62, "LARCENY": 30.72, "OTHER BURGLARY": 0.59, "RESIDENTIAL BURGLARY": 4.21, "ROBBERY": 3.16}, "year": 2019, "month": 8, "day": 20}

Edited2:我自己修复了Klaxon错误。

编辑:现在解决了这个问题后,我得到了其他东西:

08-19 23:13:32.385 2175-2175/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: studio.nyaa.crimeprediction, PID: 2175
java.lang.RuntimeException: Unable to start activity ComponentInfo{studio.nyaa.crimeprediction/studio.nyaa.crimeprediction.MainActivity}: java.io.FileNotFoundException: {"data": {"AGGRAVATED ASSAULT": 6.87, "AUTO THEFT": 4.4, "COMMERCIAL BURGLARY": 1.3, "HOMICIDE": 0.62, "LARCENY": 30.72, "OTHER BURGLARY": 0.59, "RESIDENTIAL BURGLARY": 4.21, "ROBBERY": 3.16}, "year": 2019, "month": 8, "day": 20}: open failed: ENOENT (No such file or directory)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2404)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2466)
    at android.app.ActivityThread.access$900(ActivityThread.java:175)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1369)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:135)
    at android.app.ActivityThread.main(ActivityThread.java:5418)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1037)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:832)
 Caused by: java.io.FileNotFoundException: {"data": {"AGGRAVATED ASSAULT": 6.87, "AUTO THEFT": 4.4, "COMMERCIAL BURGLARY": 1.3, "HOMICIDE": 0.62, "LARCENY": 30.72, "OTHER BURGLARY": 0.59, "RESIDENTIAL BURGLARY": 4.21, "ROBBERY": 3.16}, "year": 2019, "month": 8, "day": 20}: open failed: ENOENT (No such file or directory)
    at libcore.io.IoBridge.open(IoBridge.java:456)
    at java.io.FileInputStream.<init>(FileInputStream.java:76)
    at com.beust.klaxon.Parser$DefaultImpls.parse(Parser.kt:21)
    at com.beust.klaxon.KlaxonParser.parse(KlaxonParser.kt:9)
    at studio.nyaa.crimeprediction.MainActivityKt.obtainJson(MainActivity.kt:16)
    at studio.nyaa.crimeprediction.MainActivity$onCreate$1$json$1.invokeSuspend(MainActivity.kt:25)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:241)
    at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)
    at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:740)
 Caused by: android.system.ErrnoException: open failed: ENOENT (No such file or directory)
    at libcore.io.Posix.open(Native Method)
    at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186)
    at libcore.io.IoBridge.open(IoBridge.java:442)
    at java.io.FileInputStream.<init>(FileInputStream.java:76) 
    at com.beust.klaxon.Parser$DefaultImpls.parse(Parser.kt:21) 
    at com.beust.klaxon.KlaxonParser.parse(KlaxonParser.kt:9) 
    at studio.nyaa.crimeprediction.MainActivityKt.obtainJson(MainActivity.kt:16) 
    at studio.nyaa.crimeprediction.MainActivity$onCreate$1$json$1.invokeSuspend(MainActivity.kt:25) 
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) 
    at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:241) 
    at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594) 
    at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60) 
    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:740) 
08-19 23:13:32.555 2175-2175/? I/Process: Sending signal. PID: 2175 SIG: 9

旧内容:

尽管使用asyncawait,我仍然得到了android.os.NetworkOnMainThreadException。这是我的堆栈跟踪:

08-19 22:28:06.675 28015-28015/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: studio.nyaa.crimeprediction, PID: 28015
java.lang.RuntimeException: Unable to start activity ComponentInfo{studio.nyaa.crimeprediction/studio.nyaa.crimeprediction.MainActivity}: android.os.NetworkOnMainThreadException
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2404)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2466)
    at android.app.ActivityThread.access$900(ActivityThread.java:175)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1369)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:135)
    at android.app.ActivityThread.main(ActivityThread.java:5418)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1037)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:832)
 Caused by: android.os.NetworkOnMainThreadException
    at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1147)
    at java.net.InetAddress.lookupHostByName(InetAddress.java:418)
    at java.net.InetAddress.getAllByNameImpl(InetAddress.java:252)
    at java.net.InetAddress.getAllByName(InetAddress.java:215)
    at com.android.okhttp.HostResolver$1.getAllByName(HostResolver.java:29)
    at com.android.okhttp.internal.http.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:232)
    at com.android.okhttp.internal.http.RouteSelector.next(RouteSelector.java:124)
    at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:272)
    at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:211)
    at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:382)
    at com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:332)
    at com.android.okhttp.internal.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:199)
    at java.net.URL.openStream(URL.java:470)
    at kotlin.io.TextStreamsKt.readBytes(ReadWrite.kt:150)
    at studio.nyaa.crimeprediction.MainActivityKt.obtainJson(MainActivity.kt:17)
    at studio.nyaa.crimeprediction.MainActivity$onCreate$1$json$1.invokeSuspend(MainActivity.kt:28)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:241)
    at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:270)
    at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:79)
    at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:54)
    at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
    at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:36)
    at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
    at studio.nyaa.crimeprediction.MainActivity.onCreate(MainActivity.kt:27)
    at android.app.Activity.performCreate(Activity.java:6083)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1115)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2357)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2466) 
    at android.app.ActivityThread.access$900(ActivityThread.java:175) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1369) 
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:135) 
    at android.app.ActivityThread.main(ActivityThread.java:5418) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at java.lang.reflect.Method.invoke(Method.java:372) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1037) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:832) 

这个问题是my earlier question的变体。

3 个答案:

答案 0 :(得分:8)

这是因为异步块正在与 Dispatchers.Main 一起运行,并尝试与 Dispatchers.IO

一起使用
val json = async(Dispatchers.IO){obtainJson()}.await()

另外一种更好的语法是使用withContext

val json = withContext(Dispatchers.IO){obtainJson()}

答案 1 :(得分:1)

您不应在主线程中调用网络。您可以使用IO调度程序来修复它:

async(Dispatchers.IO){ obtainJson() }.await()

答案 2 :(得分:0)

不应在生产代码中使用runBlocking {}!它将阻塞您的主线程。

由于您是在主线程中调用此函数,因此随后每次对asynclaunch的调用都将在相同的作用域内运行,并因此在主线程上运行。

相反,您应该使用viewModelScope启动一个协程(也可以使用GlobalScope)并在主线程上运行视图更新:

GlobalScope.launch(IO) {
    val json = obtainJson()
    Log.d("postcoroutine", json.toString())
    val crime1: Double? = json.obj("data")?.double("AGGRAVATED ASSAULT")
    ...
    val year: Int? = json.int("year")
    val month: Int? = json.int("month")
    val day: Int? = json.int("day")
    launch(Main) {
        val textView1: TextView = findViewById(R.id.editText1B)
        textView1.text = crime1?.toString() ?: "N/A"
        ...
        val textViewDate: TextView = findViewById(R.id.editTextDate)
        textViewDate.text = "Date: $month/$day/$year"
    }
}

此处无需使用async。可以使用launch(Main)代替withContext(Main)