okhttp是一個第三方類庫,用於android中請求網絡。這是一個開源項目,是安卓端最火熱的輕量級框架,由移動支付Square公司貢獻(該公司還貢獻了Picasso和LeakCanary) 。用於替代HttpUrlConnection和Apache HttpClient(android API23 裏已移除HttpClient)。android
implementation 'com.squareup.okhttp3:okhttp:3.11.0'
我使用了http://www.sosoapi.com/ 來建立了一個訪問接口,用來驗證OkHttp是否請求成功。若是你有興趣瞭解,能夠直接進入網站,裏面有詳細的demo演示。後續我將不在贅述這段。git
我在請求響應裏添加了一段JSON數據:github
[ { "name": "get測試", "content": "你成功獲取了數據" } ]
這裏我寫一下解析JSON數據的方法,來解析get或者post獲得的JSON數據。後續我將不在贅述這段。json
/** * JSON 解析方法 * @param jsonData * @return */ public String readJSONContent(String jsonData){ try { StringBuffer sb = new StringBuffer(); JSONArray jsonArray = new JSONArray(jsonData); for (int i=0;i<jsonArray.length();i++){ JSONObject jsonObject = jsonArray.getJSONObject(i); sb.append(jsonObject.getString("name")+"\n"); sb.append(jsonObject.getString("content")+"\n"); } return sb.toString(); } catch (JSONException e) { Log.e("JSONException錯誤", "readContent: "+e.toString()); return e.toString(); } }
/** * 同步請求 */ public void synchro(){ Thread thread = new Thread(new Runnable() { @Override public void run() { OkHttpClient okHttpClient = new OkHttpClient();//建立單例 Request request = new Request.Builder()//建立請求 .url("http://www.sosoapi.com/pass/mock/12003/test/gettest") .build(); try { Response response = okHttpClient.newCall(request).execute();//執行請求 mContent = response.body().string();//獲得返回響應 runOnUiThread(new Runnable() { @Override public void run() { mtextView.setText(readJSONContent(mContent)); } }); } catch (IOException e) { e.printStackTrace(); Log.e("OkHttpActivity", e.toString() ); } } }); thread.start(); }
注意1:異步請求方式,請求的回調會在子線程裏,因此若是須要更新UI你須要切換到主線程。且你不須要在new 一個線程包裹這個異步請求了。另外如何切換到主線程請使用 Handler 例子:api
注意2:在異步請求方法裏,請不要將 public void onResponse(Call call, final Response response)回調裏的response回調數據放到UI線程裏解析,由於有一個天坑,有可能在UI線程裏解析的時候response裏面卻尚未塞入數據(我也以爲很神奇,不知道寫okhttp的公司是怎麼想的,爲何不處理完全部數據在提供回調)網絡
private Handler mHandler = new Handler(Looper.getMainLooper());
mHandler.post(new Runnable() { @Override public void run() { //主線程 } });
建立異步請求app
/** * get異步請求 */ public void asynchronous(){ OkHttpClient okHttpClient = new OkHttpClient(); Request request = new Request.Builder() .url("http://www.sosoapi.com/pass/mock/12003/test/gettest") .build(); okHttpClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { //失敗回調 } @Override public void onResponse(Call call, final Response response) throws IOException {
mContent = readJSONContent(response.body().string()); //響應成功,這個回調在子線程中,因此不須要建立線程 if (response.isSuccessful()){ //isSuccessful方法:若是代碼位於(200…300)中,則返回true,這意味着請求已成功接收 runOnUiThread(new Runnable() { @Override public void run() { try { //由於在子線程,因此咱們須要回到主線程中更新UI數據 mtextView.setText(mContent); } catch (IOException e) { e.printStackTrace(); } } }); } } }); }
post請求也同時有同步與異步方法,與上面一致,因此這裏就不展現了,下面咱們來看看post請求發送框架
/** * post請求 */ public void post(){ new Thread(new Runnable() { @Override public void run() { //實例 OkHttpClient okHttpClient = new OkHttpClient(); //建立post請求數據表單 RequestBody requestBody = new FormBody.Builder() .add("name","請求post") .add("password","123456") .build(); //建立請求 final Request request = new Request.Builder() .url("http://www.sosoapi.com/pass/mock/12003/test/posttest") .post(requestBody)//添加post請求 .build(); try { //發送請求獲得響應 final Response response = okHttpClient.newCall(request).execute(); runOnUiThread(new Runnable() { @Override public void run() { try { mtextView.setText(readJSONContent(response.body().string())); } catch (IOException e) { e.printStackTrace(); } } }); } catch (IOException e) { e.printStackTrace(); } } }).start(); }
效果圖:異步
取消okhttp的網絡請求很簡單隻須要async
call.cancel();
如何鑑別是網絡異常仍是主動取消,請求取消的回調在onFailure(Call call, IOException e)裏回調,這個時候咱們須要再次判斷onFailure裏回調的是咱們本身主動取消的仍是網絡異常報錯的
mCall.enqueue(new Callback() {//發送請求 @Override public void onFailure(final Call call, final IOException e) { if (call.isCanceled()){ listener.onCancel(); }else { listener.onFailure(call, e); } } //省略下面代碼...
RequestBody是okhttp post發送數據配置類.在這以前咱們先了解下回顧一下body類型
/** * 此body是 默認application/x-www-form-urlencoded,你能夠進入FormBody類查看,第一行靜態常量就是這個 */ public void FormBody(){ FormBody.Builder builder = new FormBody.Builder(); builder.add("key","content"); builder.build(); }
/** * multipart/form-data */ public void MultipartBody(){ RequestBody requestBody = new RequestBody() { @Override public MediaType contentType() { return null; } @Override public void writeTo(BufferedSink sink) throws IOException { //上傳流 sink.write() } }; MultipartBody.Builder builder = new MultipartBody.Builder(); builder.addFormDataPart("key","content");//表單數據 builder.addFormDataPart("file_key","/path/image.jpg",requestBody);//文件數據 MultipartBody multipartBody = builder.build(); }
固然,有特殊需求你還能夠添加手動其餘body類型,create也支持好幾種數據的上傳形式
/** * 手動建立4種body */ public void RequestBody(){ RequestBody applicationFormUrlencodedBody = RequestBody.create(MediaType.parse("application/x-www-form-urlencoded; charset=utf-8"),new String("demo").getBytes()); RequestBody multipartBody = RequestBody.create(MediaType.parse("multipart/form-data; charset=utf-8"),new File("/path/image.jpg")); RequestBody jsonBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"),"content"); RequestBody textbody = RequestBody.create(MediaType.parse("text/xml; charset=utf-8"),"content"); }
public class OkHttpClientCreate { private static final boolean IS_RETRY = false;//失敗是否重連 private static final int CONNECT_TIME = 10;//設置鏈接超時時間 單位:秒 private static final int READ_TIME = 10;//設置讀取超時時間 private static final int WRITE_TIME = 10;//設置寫入超時間 private static OkHttpClient mOkHttpClient; public static OkHttpClient CreateClient(){ if (mOkHttpClient == null){ return mOkHttpClient = new OkHttpClient.Builder() .retryOnConnectionFailure(IS_RETRY) .connectTimeout(CONNECT_TIME,TimeUnit.SECONDS)//鏈接超時 .readTimeout(READ_TIME,TimeUnit.SECONDS)//讀取超時 .writeTimeout(WRITE_TIME,TimeUnit.SECONDS)//寫入超時 // .callTimeout()//呼叫超時,設置此參數爲總體流程請求的超時時間 // .addInterceptor() //設置攔截器 // .authenticator() //設置認證器 // .proxy()//設置代理 .build(); } return mOkHttpClient; } public static void destroy(){ mOkHttpClient = null; } }