栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

okhttp使用错误引发的一例crash

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

okhttp使用错误引发的一例crash

class NetMainActivity : AppCompatActivity() {
    var TAG = "NetMainActivity"

    var client :OkHttpClient  = OkHttpClient()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_net_main)
        btn1.setOnClickListener {
            testGet()
        }
    }

    fun testGet() {
        var request = Request.Builder().url("http://www.baidu.com").build()
        thread {
            //错误写法
            Log.e(TAG, "testGet: Threadname1=${Thread.currentThread().name}")
            var response = client.newCall(request).execute()
            textView.post {
                Log.e(TAG, "testGet: Threadname2=${Thread.currentThread().name}")
                textView.text = response.body?.string()
            }

            //正确写法
            Log.e(TAG, "testGet: Threadname1=${Thread.currentThread().name}")
            var response = client.newCall(request).execute()
            var str = response.body?.string()
            textView.post {
                Log.e(TAG, "testGet: Threadname2=${Thread.currentThread().name}")
                textView.text = str
            }
        }
    }
}

        上面是简单使用okHttp访问网络获取返回值,然后把返回结果文本展示到textview中。

        很简单的代码,最开始写的是上面错误代码,安装app后,有时候运行能访问网络并成功展示,有时候多点几下就出现crash,并提示android.os.NetworkOnMainThreadException异常。异常堆栈如下:

2022-07-21 17:36:36.260 8066-8066/com.example.helloworld E/NetMainActivity: testGet: Threadname2=main
2022-07-21 17:36:36.280 8066-8066/com.example.helloworld E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.helloworld, PID: 8066
    android.os.NetworkOnMainThreadException
        at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1513)
        at java.net.SocketInputStream.read(SocketInputStream.java:175)
        at java.net.SocketInputStream.read(SocketInputStream.java:144)
        at okio.InputStreamSource.read(JvmOkio.kt:90)
        at okio.AsyncTimeout$source$1.read(AsyncTimeout.kt:129)
        at okio.RealBufferedSource.request(RealBufferedSource.kt:206)
        at okio.RealBufferedSource.require(RealBufferedSource.kt:199)
        at okio.RealBufferedSource.readHexadecimalUnsignedLong(RealBufferedSource.kt:381)
        at okhttp3.internal.http1.Http1ExchangeCodec$ChunkedSource.readChunkSize(Http1ExchangeCodec.kt:429)
        at okhttp3.internal.http1.Http1ExchangeCodec$ChunkedSource.read(Http1ExchangeCodec.kt:408)
        at okhttp3.internal.connection.Exchange$ResponseBodySource.read(Exchange.kt:276)
        at okio.RealBufferedSource.read(RealBufferedSource.kt:189)
        at okio.RealBufferedSource.exhausted(RealBufferedSource.kt:197)
        at okio.GzipSource.read(GzipSource.kt:88)
        at okio.Buffer.writeAll(Buffer.kt:1642)
        at okio.RealBufferedSource.readString(RealBufferedSource.kt:95)
        at okhttp3.ResponseBody.string(ResponseBody.kt:187)
        at com.example.helloworld.activity.net.NetMainActivity$testGet$1.invoke$lambda-0(NetMainActivity.kt:34)
        at com.example.helloworld.activity.net.NetMainActivity$testGet$1.lambda$o7kqc81vUHfiH5ZjT9CxIqj9Fhs(Unknown Source:0)
        at com.example.helloworld.activity.net.-$$Lambda$NetMainActivity$testGet$1$o7kqc81vUHfiH5ZjT9CxIqj9Fhs.run(Unknown Source:4)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:201)
        at android.app.ActivityThread.main(ActivityThread.java:6820)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:922)
    	Suppressed: android.os.NetworkOnMainThreadException
        at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1513)
        at java.net.SocketInputStream.read(SocketInputStream.java:175)
        at java.net.SocketInputStream.read(SocketInputStream.java:144)
        at okio.InputStreamSource.read(JvmOkio.kt:90)
        at okio.AsyncTimeout$source$1.read(AsyncTimeout.kt:129)
        at okio.RealBufferedSource.indexOf(RealBufferedSource.kt:427)
        at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.kt:320)
        at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.kt:105)
        at okhttp3.internal.http1.Http1ExchangeCodec$ChunkedSource.readChunkSize(Http1ExchangeCodec.kt:426)
        at okhttp3.internal.http1.Http1ExchangeCodec$ChunkedSource.read(Http1ExchangeCodec.kt:408)
        at okhttp3.internal.Util.skipAll(Util.kt:337)
        at okhttp3.internal.Util.discard(Util.kt:358)
        at okhttp3.internal.http1.Http1ExchangeCodec$ChunkedSource.close(Http1ExchangeCodec.kt:450)
        at okio.ForwardingSource.close(ForwardingSource.kt:34)
        at okhttp3.internal.connection.Exchange$ResponseBodySource.close(Exchange.kt:309)
        at okio.RealBufferedSource.close(RealBufferedSource.kt:477)
        at okio.RealBufferedSource.close(RealBufferedSource.kt:477)
        at okio.InflaterSource.close(InflaterSource.kt:136)
        at okio.GzipSource.close(GzipSource.kt:171)
        at okio.RealBufferedSource.close(RealBufferedSource.kt:477)
        at kotlin.io.CloseableKt.closeFinally(Closeable.kt:60)
        at okhttp3.ResponseBody.string(ResponseBody.kt:186)
        		... 10 more
2022-07-21 17:36:36.343 1030-1116/? E/InputDispatcher: channel 'b58ae29 com.example.helloworld/com.example.helloworld.activity.net.NetMainActivity (server)' ~ Channel is unrecoverably broken and will be disposed!

NetworkOnMainThreadException异常代表有在主线程执行网络请求相关操作。可是

var response = client.newCall(request).execute()

网络请求的这部分代码明明是在子线程执行的啊。

接着我在代码中打印了两行日志。日志内容为

2022-07-21 17:36:36.122 8066-8111/com.example.helloworld E/NetMainActivity: testGet: Threadname1=Thread-2
2022-07-21 17:36:36.260 8066-8066/com.example.helloworld E/NetMainActivity: testGet: Threadname2=main
2022-07-21 17:36:36.280 8066-8066/com.example.helloworld E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.helloworld, PID: 8066
    android.os.NetworkOnMainThreadException
        at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1513)
...

可以看到client的excute()是在子线程执行的。并且当我们获取到response对象,把response的body展示到textview上是在主线程执行的,这一点从log和代码都能看出来。

        那究竟是哪里的网络操作在主线程中操作了呢?

        我尝试了下先在子线程中把response.body.string()字符串先在子线程中获取到了,再在主线程中设置textview。就是上面正确的代码。

        结果我发现怎么点击都能正常访问网络并成功展示了。那看来response.body.string()中应该是有一些网络操作了。之前以为只要拿到Response对象就以为已经执行完网络操作返回结果了,看来是自己天真了。

        来看Response#string()的源码,里面有一句话特别重要:This method loads entire response body into memory.If the response body is very large thismay trigger an [OutOfMemoryError]意思是这个函数是用来加载整个response结果到内存中,response结果可能会很大,所以重点来啦,这是一个耗时动作!!!耗时动作是不能在主线程中执行的,所以我们上面在主线程中执行string()引发了crash。

@Throws(IOException::class)
fun string(): String = source().use { source ->
  source.readString(charset = source.readBomAsCharset(charset()))
}

        response.body.string()具体怎样引发的crash后面有时间再分析吧!!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1024389.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号