前言
在Android開發(fā)中,OKhttp已經(jīng)成為眼下最火的http請(qǐng)求框架划址,那么OKhttp有什么過人之處呢蛀骇?接下來就對(duì)OKhttp的學(xué)習(xí)進(jìn)行總結(jié)和泌。
一. OKhttp優(yōu)勢(shì):
OkHttp 是一個(gè)高效的 http 客戶端评汰,特點(diǎn)如下:
- 支持 http2(基于SPDY協(xié)議) 協(xié)議纷捞,對(duì)同一個(gè)主機(jī)的所有請(qǐng)求允許使用同一個(gè) socket;
- 如果 http2 不可用被去,使用鏈接池技術(shù)來降低了請(qǐng)求響應(yīng)的延遲主儡;
- 使用透明的 gzip 壓縮減少了數(shù)據(jù)流量;
- 使用網(wǎng)絡(luò)緩存避免了重復(fù)的網(wǎng)絡(luò)請(qǐng)求惨缆。
拓展--SPDY協(xié)議:SPDY協(xié)議是Google提出的基于傳輸控制協(xié)議(TCP)的應(yīng)用層協(xié)議糜值,通過壓縮、多路復(fù)用和優(yōu)先級(jí)來縮短加載時(shí)間踪央。該協(xié)議是一種更加快速的內(nèi)容傳輸協(xié)議臀玄。SPDY協(xié)議相比于HTTP的優(yōu)勢(shì)在于:
- 復(fù)用連接瓢阴,可在一個(gè)TCP連接上傳送多個(gè)資源畅蹂。應(yīng)對(duì)了TCP慢啟動(dòng)的特性。
- 請(qǐng)求分優(yōu)先級(jí)荣恐,重要的資源優(yōu)先傳送液斜。
- HTTP頭部數(shù)據(jù)也被壓縮累贤,省流量。
- 服務(wù)器端可主動(dòng)連接客戶端來推送資源(Server Push)少漆。
二. OKhttp的主要功能:
- 發(fā)送get臼膏,post請(qǐng)求;
- 文件的上傳示损,下載渗磅;
- 加載圖片(內(nèi)部會(huì)根據(jù)圖片的大小進(jìn)行壓縮);
- 支持請(qǐng)求回調(diào)检访,直接返回對(duì)象或者對(duì)象集合始鱼;
- 支持session的保持。
三. OKhttp的基本使用:
OKhttp使用之前需要添加依賴:
compile "com.squareup.okhttp:okhttp:3.2.0"
清單文件中添加網(wǎng)絡(luò)訪問權(quán)限:
<uses-permission android:name="android.permission.INTERNET"/>
1. get請(qǐng)求和post請(qǐng)求的區(qū)別:
- get是從服務(wù)器上獲取數(shù)據(jù)脆贵,post是向服務(wù)器上傳輸數(shù)據(jù)医清。
- get是把參數(shù)數(shù)據(jù)隊(duì)列加到提交表單的ACTION屬性所指的URL中,值和表單內(nèi)各個(gè)字段一一對(duì)應(yīng)卖氨,在URL中可以看到会烙。post是通過HTTP post機(jī)制,將表單內(nèi)各個(gè)字段與其內(nèi)容放置在HTML HEADER內(nèi)一起傳送到ACTION屬性所指的URL地址筒捺。用戶看不到這個(gè)過程柏腻。
- 對(duì)于get方式,服務(wù)器端用Request.QueryString獲取變量的值焙矛,對(duì)于post方式葫盼,服務(wù)器端用Request.Form獲取提交的數(shù)據(jù)。
- get傳送的數(shù)據(jù)量較小村斟,不能大于2KB贫导。post傳送的數(shù)據(jù)量較大,一般被默認(rèn)為不受限制蟆盹。但理論上孩灯,IIS4中最大量為80KB,IIS5中為100KB逾滥。
- get安全性非常低峰档,post安全性較高。但是執(zhí)行效率卻比Post方法好寨昙。
- get可以被瀏覽器緩存讥巡,post不可以。
- get請(qǐng)求是安全的舔哪,post不安全欢顷。
- 項(xiàng)目開發(fā)中,當(dāng)涉及到參數(shù)的安全問題或者參數(shù)比較大的時(shí)候捉蚤,應(yīng)該使用Post請(qǐng)求方式(例如:登錄抬驴,注冊(cè)炼七,上傳,支付布持,下單)豌拙;如果是相對(duì)簡(jiǎn)單的查詢類接口可以使用Get請(qǐng)求方式(例如:獲取圖片,獲取文章詳情)题暖。
2. 同步/異步發(fā)送get請(qǐng)求:
(1) 創(chuàng)建OkHttpClient對(duì)象:
OkHttpClient okHttpClient = new OkHttpClient();
(2) 使用Request.Builder構(gòu)建請(qǐng)求對(duì)象:
Request類封裝了請(qǐng)求報(bào)文信息:請(qǐng)求的Url地址按傅、請(qǐng)求的方法(如GET、POST等)胧卤、各種請(qǐng)求頭(如Content-Type逞敷、Cookie)以及可選的請(qǐng)求體。一般通過內(nèi)部類Request.Builder的鏈?zhǔn)秸{(diào)用生成Request對(duì)象灌侣。
Request request = new Request.Builder()
.url(URL)
.build();
(3) 創(chuàng)建一個(gè)call對(duì)象推捐,對(duì)象是response,發(fā)送請(qǐng)求
Call代表了一個(gè)實(shí)際的HTTP請(qǐng)求侧啼,它是連接Request和Response的橋梁牛柒,通過Request對(duì)象的newCall()方法可以得到一個(gè)Call對(duì)象。Call對(duì)象既支持同步獲取數(shù)據(jù)痊乾,也可以異步獲取數(shù)據(jù)皮壁。
執(zhí)行Call對(duì)象的execute()方法,會(huì)阻塞當(dāng)前線程去獲取數(shù)據(jù)哪审,該方法返回一個(gè)Response對(duì)象蛾魄。
-
執(zhí)行Call對(duì)象的enqueue()方法,不會(huì)阻塞當(dāng)前線程湿滓,該方法接收一個(gè)Callback對(duì)象滴须,當(dāng)異步獲取到數(shù)據(jù)之后,會(huì)回調(diào)執(zhí)行Callback對(duì)象的相應(yīng)方法叽奥。如果請(qǐng)求成功扔水,則執(zhí)行Callback對(duì)象的onResponse方法,并將Response對(duì)象傳入該方法中朝氓;如果請(qǐng)求失敗魔市,則執(zhí)行Callback對(duì)象的onFailure方法。
Call call = okHttpClient.newCall(request);
(4) 通過調(diào)用execute()發(fā)送同步請(qǐng)求,調(diào)用enqueue()發(fā)送異步請(qǐng)求,獲取到response對(duì)象
Response類封裝了響應(yīng)報(bào)文信息:狀態(tài)嗎(200赵哲、404等)待德、響應(yīng)頭(Content-Type、Server等)以及可選的響應(yīng)體枫夺〗埽可以通過Call對(duì)象的execute()方法獲得Response對(duì)象,異步回調(diào)執(zhí)行Callback對(duì)象的onResponse方法時(shí)也可以獲取Response對(duì)象。
//調(diào)用execute()發(fā)送同步請(qǐng)求
try {
Response response = call.execute();
//判斷請(qǐng)求是否成功
if(response.isSuccessful()) {
Log.i("TAG",response.body().string());
response.body().close();
}
//關(guān)閉body
response.body().close();
} catch (IOException e) {
e.printStackTrace();
}
//通過調(diào)用enqueue()發(fā)送異步請(qǐng)求,異步請(qǐng)求開啟了新的線程執(zhí)行網(wǎng)絡(luò)請(qǐng)求
call.enqueue(new Callback() {
@Override
public void onFailure(Request request, IOException e) {
//請(qǐng)求失敗的回調(diào)方法
}
@Override
public void onResponse(Response response) throws IOException {
//請(qǐng)求成功的回調(diào)方法
String result = response.body().string();
Log.i("TAG",result);
//關(guān)閉body
response.body().close();
}
});
3. 同步/異步發(fā)送post請(qǐng)求:
public static final MediaType JSON = MediaType
.parse("application/json; charset=utf-8");
public static final String json = "{android: hello world!}";
/**
* 同步發(fā)送post請(qǐng)求提交json數(shù)據(jù)
*/
OkHttpClient okhttpClient = new OkHttpClient();
//創(chuàng)建一個(gè)RequestBody對(duì)象(參數(shù)1:參數(shù)類型涧偷,參數(shù)2:傳輸?shù)膉son串)
RequestBody requestBody = RequestBody.create(JSON,json);
//創(chuàng)建一個(gè)請(qǐng)求對(duì)象
Request request = new Request.Builder()
.url(URL)
.post(requestBody)
.build();
//發(fā)送同步請(qǐng)求,獲取響應(yīng)對(duì)象
Call call = okhttpClient.newCall(request);
try {
Response response = call.execute();
//判斷請(qǐng)求是否成功
if(response.isSuccessful()) {
Log.i("TAG",response.body().string());
response.body().close();
}
} catch (IOException e) {
e.printStackTrace();
}
/**
* 異步發(fā)送post請(qǐng)求提交鍵值對(duì)
*/
OkHttpClient okHttpClient = new OkHttpClient();
//創(chuàng)建一個(gè)請(qǐng)求體
RequestBody requestBody = new FormEncodingBuilder()
.add("name","張三")
.add("age","24")
.add("sex","男")
.build();
//創(chuàng)建一個(gè)請(qǐng)求對(duì)象
Request request = new Request.Builder()
.url(URL)
.post(requestBody)
.build();
//發(fā)送異步請(qǐng)求毙死,獲取響應(yīng)對(duì)象
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Request request, IOException e) {
}
@Override
public void onResponse(Response response) throws IOException {
//判斷請(qǐng)求是否成功
if(response.isSuccessful()) {
Log.i("TAG",response.body().string());
response.body().close();
}
}
});
OkHttp的簡(jiǎn)單封裝 :
在項(xiàng)目中使用okhttp作為網(wǎng)絡(luò)訪問框架的時(shí)候燎潮,還是要對(duì)其封裝使用的,下面就簡(jiǎn)單的封裝一下:
public class OkHttpManager {
public static OkHttpManager instence;
private OkHttpClient mOkHttpClient;
private Handler okHandler;
private OkHttpManager() {
//聲明Handler對(duì)指定為主線程looper,確保執(zhí)行線程在主線程中扼倘。
okHandler = new Handler(Looper.getMainLooper());
//指定超時(shí)時(shí)間等參數(shù)
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS);
mOkHttpClient = builder.build();
}
/**
* 獲取當(dāng)前的實(shí)例對(duì)象确封,確保唯一性
*/
public static OkHttpManager getInstence() {
if (instence == null) {
synchronized (OkHttpManager.class) {
if (instence == null) {
instence = new OkHttpManager();
}
}
}
return instence;
}
/**
* 發(fā)送get請(qǐng)求
*
* @param url
* @param resultCallback
*/
public void getNet(String url, ResultCallback resultCallback) {
Request request = new Request.Builder()
.url(url) //接口地址
.method("GET", null) //默認(rèn)的也是GET,可以不設(shè)置
.build();
dealNet(request,resultCallback);
}
/**
* 發(fā)送post請(qǐng)求
*
* @param url
* @param resultCallback
* @param param 傳入數(shù)量不定的參數(shù)
*/
public void postNet(String url, ResultCallback resultCallback, Param... param) {
if (param == null) {
param = new Param[0];
}
FormBody.Builder frombody = new FormBody.Builder();
for (Param p : param) {
frombody.add(p.key, p.value);
}
RequestBody requestBody = frombody.build();
Request request = new Request.Builder()
.url(url)
.post(requestBody) //傳入構(gòu)建好的參數(shù)
.build();
dealNet(request,resultCallback);
}
/**
* 網(wǎng)絡(luò)請(qǐng)求
*
* @param request 請(qǐng)求
* @param resultCallback 自定義的監(jiān)聽回調(diào)
*/
public void dealNet(final Request request, final ResultCallback resultCallback) {
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, final IOException e) {
okHandler.post(new Runnable() {
@Override
public void run() {
//請(qǐng)求失敗的時(shí)候執(zhí)行的方法
resultCallback.onFailed(request, e);
}
});
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
String str = "";
try {
str = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
final String finalStr = str;
Log.i("OkHttpManager", "onResponse" + finalStr);
okHandler.post(new Runnable() {
@Override
public void run() {
//請(qǐng)求成功的時(shí)候執(zhí)行的方法
resultCallback.onSuccess(finalStr);
}
});
}
});
}
/**
* 自定義監(jiān)聽回調(diào)
*/
public static abstract class ResultCallback {
public abstract void onFailed(Request request, IOException e);
public abstract void onSuccess(String response);
}
/**
* 參數(shù)封裝類
*/
public static class Param {
String key;
String value;
public Param() {
}
public Param(String key, String value) {
this.key = key;
this.value = value;
}
}
}