關于OkHttp中response.body().string()的用法解析
OkHttp中response.body().string()解析
在多次引用response.body().string()的時候,程序會崩潰掉。
下面通過源碼分析:
ResponseBody body = response.body();//獲取響應體
Response中的string()方法如下:
? public final String string() throws IOException { ? //通過使用指定的 charset 解碼指定的 byte 數(shù)組,構(gòu)造一個新的 String ? ? return new String(bytes(), charset().name()); ? }
對于bytes()方法
public final byte[] bytes() throws IOException { ? ? long contentLength = contentLength(); ? ? if (contentLength > Integer.MAX_VALUE) { ? ? ? throw new IOException("Cannot buffer entire body for content length: " + contentLength); ? ? } ? ? BufferedSource source = source(); ? ? byte[] bytes; ? ? try { ? ? ? bytes = source.readByteArray(); ? ? } finally { ? ? ? Util.closeQuietly(source); ? ? } ? ? if (contentLength != -1 && contentLength != bytes.length) { ? ? ? throw new IOException("Content-Length and stream length disagree"); ? ? } ? ? return bytes; ? }
可以看到,在finally中,執(zhí)行了資源的關閉操作。
在拿到資源之后,就將資源關閉了,所以只能獲取一次實體。
對于charset()方法
private Charset charset() { ?MediaType contentType = contentType(); ?return contentType != null ? contentType.charset(UTF_8) : UTF_8; ? }
public static final Charset UTF_8 = Charset.forName("UTF-8");
根據(jù)響應頭中的contentType 決定編碼形式。轉(zhuǎn)換為UTF-8.
OkHttp的坑:response.body().string() 只能調(diào)用一次
發(fā)現(xiàn)
在接微信登錄時,通過構(gòu)造 OkHttpClient 對象發(fā)起一次請求并加入隊列,待服務端響應后,回調(diào) Callback 接口觸發(fā) onResponse() 方法,然后在該方法中通過 Response 對象處理返回結(jié)果、實現(xiàn)業(yè)務邏輯。
大致代碼如下
? private void getUserInfo() { ? ? ? ? String path = "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken + "&openid=" + openid; ? ? ? ? OkHttpClient client = new OkHttpClient(); ? ? ? ? Request request = new Request.Builder() ? ? ? ? ? ? ? ? .url(path) ? ? ? ? ? ? ? ? .build(); ? ? ? ? Call call = client.newCall(request); ? ? ? ? call.enqueue(new Callback() { ? ? ? ? ? ? @Override ? ? ? ? ? ? public void onFailure(Call call, IOException e) { ? ? ? ? ? ? ? ? Log.d(TAG, "onFailure: userinfo" + e.getMessage()); ? ? ? ? ? ? ? ? finish(); ? ? ? ? ? ? } ? ? ? ? ? ? @Override ? ? ? ? ? ? public void onResponse(Call call, Response response) throws IOException { // ? ? ? ? ? ? ? ?Log.d(TAG, "onResponse: userinfo" + response.body().string()); ? ?//okhttp中 response.body().string()只允許調(diào)用一次 ? ? ? ? ? ? ? ? final String result = response.body().string(); ? ? ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? ? ? JSONObject jsonObject = new JSONObject(result); ? ? ? ? ? ? ? ? ? ? unionId = jsonObject.getString("unionid"); ? ? ? ? ? ? ? ? ? ? headImgUrl = jsonObject.getString("headimgurl"); ? ? ? ? ? ? ? ? ? ? nickname = jsonObject.getString("nickname"); ? ? ? ? ? ? ? ? ? ? Log.d(TAG,"getUserInfo: unionId = "+unionId+" ?headImgUrl = "+ headImgUrl + " ?nickname = "+ nickname); ? ? ? ? ? ? ? ? } catch (JSONException e) { ? ? ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? finish(); ? ? ? ? ? ? } ? ? ? ? }); ? ? }
在 onResponse() 中,為便于調(diào)試,我打印了返回體,然后通過 parseResponseStr() 方法解析返回體(注意:這兒兩次調(diào)用了 response.body().string())。
這段看起來沒有任何問題的代碼,實際運行后卻出了問題,,通過debug發(fā)現(xiàn)result在轉(zhuǎn)換成jsonObject時為null。
那為什么result會變?yōu)閚ull呢?通過網(wǎng)上資料查閱發(fā)現(xiàn),response.body().string()只能調(diào)用一次,調(diào)用完就會釋放掉資源,恍然大悟。。。
然后我點進源碼看了一下:
public final String string() throws IOException { ? ? BufferedSource source = source(); ? ? try { ? ? ? Charset charset = Util.bomAwareCharset(source, charset()); ? ? ? return source.readString(charset); ? ? } finally { ? ? ? Util.closeQuietly(source); ? ? } ? } Util.closeQuietly(source);
很棒,原來在我們調(diào)用了response.body的String()方法之后OkHttp 將響應體的緩沖資源返回的同時,調(diào)用 closeQuietly() 方法默默釋放了資源。
就是這個原因了。Get√
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
Android開發(fā)Kotlin語言協(xié)程中的并發(fā)問題和互斥鎖
Android開發(fā)Kotlin語言提供了多種機制來處理并發(fā)和同步,其中包括高層次和低層次的工具,對于常規(guī)的并發(fā)任務,可以利用 Kotlin 協(xié)程提供的結(jié)構(gòu)化并發(fā)方式,而對于需要更低層次的鎖定機制,可以使用Mutex(互斥鎖)來實現(xiàn)對共享資源的線程安全訪問2024-06-06Android中使用ZXing生成二維碼(支持添加Logo圖案)
ZXing是谷歌的一個開源庫,可以用來生成二維碼、掃描二維碼。接下來通過本文給大家介紹Android中使用ZXing生成二維碼(支持添加Logo圖案),需要的朋友參考下2017-01-01Android隱私協(xié)議提示彈窗的實現(xiàn)流程詳解
這篇文章主要介紹了Android隱私協(xié)議提示彈窗的實現(xiàn)流程,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習吧2023-01-01Android實現(xiàn)動態(tài)顯示或隱藏密碼輸入框的內(nèi)容
這篇文章主要介紹了Android實現(xiàn)動態(tài)顯示或隱藏密碼輸入框的內(nèi)容,主要通過設置EditText的setTransformationMethod()方法來實現(xiàn),需要的朋友可以參考下2014-09-09Android studio實現(xiàn)簡易計算器App功能
這篇文章主要為大家詳細介紹了Android studio實現(xiàn)簡易計算器App功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-05-05Android 中API之Drawable資源詳解及簡單實例
這篇文章主要介紹了Android 中API之Drawable資源詳解及簡單實例的相關資料,需要的朋友可以參考下2017-05-05