關(guān)于OkHttp中response.body().string()的用法解析
OkHttp中response.body().string()解析
在多次引用response.body().string()的時(shí)候,程序會(huì)崩潰掉。
下面通過(guò)源碼分析:
ResponseBody body = response.body();//獲取響應(yīng)體
Response中的string()方法如下:
? public final String string() throws IOException {
? //通過(guò)使用指定的 charset 解碼指定的 byte 數(shù)組,構(gòu)造一個(gè)新的 String
? ? return new String(bytes(), charset().name());
? }對(duì)于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í)行了資源的關(guān)閉操作。
在拿到資源之后,就將資源關(guān)閉了,所以只能獲取一次實(shí)體。
對(duì)于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ù)響應(yīng)頭中的contentType 決定編碼形式。轉(zhuǎn)換為UTF-8.
OkHttp的坑:response.body().string() 只能調(diào)用一次
發(fā)現(xiàn)
在接微信登錄時(shí),通過(guò)構(gòu)造 OkHttpClient 對(duì)象發(fā)起一次請(qǐng)求并加入隊(duì)列,待服務(wù)端響應(yīng)后,回調(diào) Callback 接口觸發(fā) onResponse() 方法,然后在該方法中通過(guò) Response 對(duì)象處理返回結(jié)果、實(shí)現(xiàn)業(yè)務(wù)邏輯。
大致代碼如下
? 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)試,我打印了返回體,然后通過(guò) parseResponseStr() 方法解析返回體(注意:這兒兩次調(diào)用了 response.body().string())。
這段看起來(lái)沒(méi)有任何問(wèn)題的代碼,實(shí)際運(yùn)行后卻出了問(wèn)題,,通過(guò)debug發(fā)現(xiàn)result在轉(zhuǎn)換成jsonObject時(shí)為null。
那為什么result會(huì)變?yōu)閚ull呢?通過(guò)網(wǎng)上資料查閱發(fā)現(xiàn),response.body().string()只能調(diào)用一次,調(diào)用完就會(huì)釋放掉資源,恍然大悟。。。
然后我點(diǎn)進(jìn)源碼看了一下:
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);很棒,原來(lái)在我們調(diào)用了response.body的String()方法之后OkHttp 將響應(yīng)體的緩沖資源返回的同時(shí),調(diào)用 closeQuietly() 方法默默釋放了資源。
就是這個(gè)原因了。Get√
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
解決Android Device Monitor 的 File Explorer 中無(wú)法打開(kāi)某些文件夾的問(wèn)題
這篇文章主要介紹了解決Android Device Monitor 的 File Explorer 中無(wú)法打開(kāi)某些文件夾的問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04
設(shè)置界面開(kāi)發(fā)Preference Library數(shù)據(jù)重建機(jī)制詳解
這篇文章主要為大家介紹了設(shè)置界面開(kāi)發(fā)利器Preference Library數(shù)據(jù)重建機(jī)制詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10
Android開(kāi)發(fā)之MediaPlayer基本使用方法詳解
這篇文章主要介紹了Android開(kāi)發(fā)之MediaPlayer基本使用方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了MediaPlayer中的常用函數(shù)與基本使用技巧,需要的朋友可以參考下2017-05-05
Android中不支持動(dòng)態(tài)申請(qǐng)權(quán)限的原因
這篇文章主要介紹了Android中不支持動(dòng)態(tài)申請(qǐng)權(quán)限的原因,本文列舉了幾個(gè)不支持動(dòng)態(tài)申請(qǐng)權(quán)限的原因,需要的朋友可以參考下2015-01-01
Android開(kāi)發(fā)之ProgressDialog進(jìn)度對(duì)話框用法示例
這篇文章主要介紹了Android開(kāi)發(fā)之ProgressDialog進(jìn)度對(duì)話框用法,簡(jiǎn)單介紹了ProgressDialog進(jìn)度對(duì)話框常見(jiàn)函數(shù)功能,并結(jié)合實(shí)例形式分析了ProgressDialog組件創(chuàng)建及使用進(jìn)度對(duì)話框相關(guān)操作技巧,需要的朋友可以參考下2019-03-03
Java4Android開(kāi)發(fā)教程(三)java基本概念
本文介紹了Java4Android的基本概念,都是開(kāi)發(fā)必備的基礎(chǔ)知識(shí),希望能對(duì)大家有所幫助2014-10-10
詳解Android studio 動(dòng)態(tài)fragment的用法
這篇文章主要介紹了Android studio 動(dòng)態(tài)fragment的用法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10

