溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Android OkHttp, 一行代碼 OkHttp提升請求穩(wěn)定性

發(fā)布時(shí)間:2020-09-04 16:10:25 來源:網(wǎng)絡(luò) 閱讀:358 作者:Android丶VG 欄目:移動(dòng)開發(fā)

OkHttp是可以說是Android開發(fā)中,每個(gè)項(xiàng)目都必需依賴的網(wǎng)絡(luò)庫,我們可以很便捷高效的處理網(wǎng)絡(luò)請求,極大的提升了編碼效率。但是有時(shí)候,我們使用OkHttp也會(huì)遇到這樣的問題

一.崩潰的stacktrace

E AndroidRuntime: FATAL EXCEPTION: OkHttp Dispatcher
E AndroidRuntime: Process: com.example.okhttpexceptionsample, PID: 13564
E AndroidRuntime: java.lang.NullPointerException: blablabla
E AndroidRuntime:    at com.example.okhttpexceptionsample.MainActivity$createNPEInterceptor$1.intercept(MainActivity.kt:61)
E AndroidRuntime:    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:112)
E AndroidRuntime:    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:87)
E AndroidRuntime:    at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.kt:184)
E AndroidRuntime:    at okhttp3.RealCall$AsyncCall.run(RealCall.kt:136)
E AndroidRuntime:    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
E AndroidRuntime:    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
E AndroidRuntime:    at java.lang.Thread.run(Thread.java:784)

二.為什么會(huì)崩潰

從上面的stacktrace,我們可以分析到,發(fā)生了NullPointerException。發(fā)生了崩潰。

等等,我記得OkHttp有處理異常的情況呢。

嗯,確實(shí),OkHttp有處理異常的情況,比如發(fā)生異常會(huì)調(diào)用onFailure。比如下面的Callback的內(nèi)容介紹。

interface Callback {
  /**
   * Called when the request could not be executed due to cancellation, a connectivity problem or
   * timeout. Because networks can fail during an exchange, it is possible that the remote server
   * accepted the request before the failure.
   */
  fun onFailure(call: Call, e: IOException)

  /**
   * Called when the HTTP response was successfully returned by the remote server. The callback may
   * proceed to read the response body with [Response.body]. The response is still live until its
   * response body is [closed][ResponseBody]. The recipient of the callback may consume the response
   * body on another thread.
   *
   * Note that transport-layer success (receiving a HTTP response code, headers and body) does not
   * necessarily indicate application-layer success: `response` may still indicate an unhappy HTTP
   * response code like 404 or 500.
   */
  @Throws(IOException::class)
  fun onResponse(call: Call, response: Response)
}

是的.

  • OkHttp只處理了IOException的情況,
  • NullPointerException不是IOException的子類

所以沒有被處理,發(fā)生了崩潰。

那么有沒有辦法解決,讓這種崩潰不發(fā)生,對用戶不進(jìn)行干擾呢?其實(shí)是可以的。

三.使用Interceptor

package com.example.okhttpexceptionsample

import okhttp3.Interceptor
import okhttp3.Response
import java.io.IOException

/**
 * 對于Interceptor的intercept中可能出現(xiàn)的Throwable包裹成IOExceptionWrapper,轉(zhuǎn)成網(wǎng)絡(luò)請求失敗,而不是應(yīng)用崩潰
 */
class SafeGuardInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        try {
            return chain.proceed(chain.request())
        } catch (t: Throwable) {
            throw IOExceptionWrapper("SafeGuarded when requesting ${chain.request().url}", t)
        }
    }
}

/**
 * 將chain.proceed處理中發(fā)生的Throwable包裝成IOExceptionWrapper
 */
class IOExceptionWrapper(message: String?, cause: Throwable?) : IOException(message, cause)

上面的代碼,我們將任何Throwable的轉(zhuǎn)成IOExceptionWrapper(偽裝成IOException),然后添加到OkHttpClient中

fun createOKHttpClient(): OkHttpClient {
        return OkHttpClient.Builder()
            .addInterceptor(SafeGuardInterceptor())
            .build()
    }

當(dāng)我們再次執(zhí)行有NPE的代碼,日志就發(fā)生了改變(不再是崩潰的日志,而是異常的日志)

W System.err: com.example.okhttpexceptionsample.IOExceptionWrapper: SafeGuarded=blablabla
  W System.err:   at com.example.okhttpexceptionsample.SafeGuardInterceptor.intercept(SafeGuardInterceptor.kt:12)
  W System.err:   at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:112)
  W System.err:   at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:87)
  W System.err:   at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.kt:184)
  W System.err:   at okhttp3.RealCall$AsyncCall.run(RealCall.kt:136)
  W System.err:   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
  W System.err:   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
  W System.err:   at java.lang.Thread.run(Thread.java:784)
  W System.err: Caused by: java.lang.NullPointerException: blablabla
  W System.err:   at com.example.okhttpexceptionsample.MainActivity$createNPEInterceptor$1.intercept(MainActivity.kt:61)
  W System.err:   at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:112)
  W System.err:   at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:87)
  W System.err:   at com.example.okhttpexceptionsample.SafeGuardInterceptor.intercept(SafeGuardInterceptor.kt:10)
  W System.err:   ... 7 more

上述需要注意兩點(diǎn)

  • 添加的是Interceptor,而不是NetworkInterceptor
  • 順序很重要,一定要放在第一個(gè)位置

    四.這么做有什么問題

    這么做,當(dāng)然可以明顯增強(qiáng)請求的穩(wěn)定性和應(yīng)用的崩潰率。但是是不是也有一些問題呢?比如

  • 將問題情況吞掉,不利于發(fā)現(xiàn)問題呢
    確實(shí)可能存在上述的問題,但是我們可以利用下面的方式減輕或者解決問題
  • 只針對release情況應(yīng)用SafeGuardInterceptor,這樣便于debug情況下更容易發(fā)現(xiàn)
  • 針對不同的build variants進(jìn)行配置,便于盡可能的小范圍發(fā)現(xiàn)問題
  • 實(shí)行更加智能的動(dòng)態(tài)開啟策略。

在軟件工程中,很多決定都是trade-off的體現(xiàn),具體的實(shí)施方案大家可以自行平衡選擇。

關(guān)于我

更多Android高級面試合集放在github上面了
,需要的小伙伴可以點(diǎn)擊關(guān)于我?聯(lián)系我獲取
非常希望和大家一起交流 , 共同進(jìn)步

目前是一名程序員,不僅分享 Android開發(fā)相關(guān)知識(shí),同時(shí)還分享技術(shù)人成長歷程,包括個(gè)人總結(jié),職場經(jīng)驗(yàn),面試經(jīng)驗(yàn)等,希望能讓你少走一點(diǎn)彎路。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI