1、HTTP協(xié)議回顧:
01,HTTP協(xié)議概述
WEB瀏覽器與WEB服務器之間的一問一答的交互過程必須遵循一定的規(guī)則佛寿,這個規(guī)則就是HTTP協(xié)議幌墓。
02,HTTP是HyperText Transfer Protocol(超文本傳輸協(xié)議)
它是TCP/IP協(xié)議的一個應用層協(xié)議,用于定義WEB瀏覽器與WEB服務器之間交換數(shù)據(jù)的過程及數(shù)據(jù)本身的格式冀泻。
Http協(xié)議是一種應用層協(xié)議常侣,它通過TCP實現(xiàn)了可靠的數(shù)據(jù)傳輸,能夠保證數(shù)據(jù)的完整性弹渔、正確性胳施,
而TCP對于數(shù)據(jù)傳輸控制的優(yōu)點也能夠體現(xiàn)在Http協(xié)議上,使得Http的數(shù)據(jù)傳輸吞吐量肢专、效率得到保證
03,請求格式
請求:
請求行 : 請求方式 請求路徑 版本
請求頭 : 以key-value形式組成舞肆,K:V焦辅。。椿胯。
空行
請求體 : 用于數(shù)據(jù)傳遞:get方式?jīng)]有請求體(參數(shù)地址傳遞) post方式有請求體
響應:
響應行 :版本 響應碼 響應信息
響應頭 :以key-value形式組成筷登,K:V。压状。仆抵。
空行
響應體 :響應正文
04,常永請求頭
Host: www.baidu.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Cache-Control: max-age=0
Content-Type: text/html
Content-Length:120
05,請求方式
Get:請求獲取Request-URI所標識的資源
POST:在Request-URI所標識的資源后附加新的數(shù)據(jù)
HEAD 請求獲取由Request-URI所標識的資源的響應信息報頭
PUT:請求服務器存儲一個資源跟继,并用Request-URI作為其標識
DELETE:請求服務器刪除Request-URI所標識的資源
TRACE:請求服務器回送收到的請求信息种冬,主要用于測試或診斷
CONNECT:保留將來使用
OPTIONS:請求查詢服務器的性能,或者查詢與資源相關的選項
GET方式(以在請求的URL地址后以?的形式帶上交給服務器的數(shù)據(jù)舔糖,多個數(shù)據(jù)之間以&進行分隔,通常傳送的數(shù)據(jù)不超過1kb)娱两,
通過請求URI得到資源。一般用于獲取/查詢資源信息
POST方式(在請求的正文內(nèi)容中向服務器發(fā)送數(shù)據(jù),傳送的數(shù)據(jù)無限制)金吗,
用于向服務器提交新的內(nèi)容十兢。一般用于更新資源信息
06,狀態(tài)碼
200(正常),206請求部分數(shù)據(jù)
302/307(臨時重定向),
304(未修改),
403(訪問被拒絕) --? user-Aqent
404(找不到),
500(服務器內(nèi)部錯誤)
06Http協(xié)議的特點
1支持客戶/服務器模式。
2簡單快速:客戶向服務器請求服務時摇庙,只需傳送請求方法和路徑旱物。請求方法常用的有GET、 HEAD卫袒、POST宵呛。每種方法規(guī)定了客戶與服務器聯(lián)系的類型不同。 由于HTTP協(xié)議簡單夕凝,使得HTTP服務器的程序規(guī)模小宝穗,因而通信速度很快。
3靈活:HTTP允許傳輸任意類型的數(shù)據(jù)對象码秉。正在傳輸?shù)念愋陀蒀ontent-Type加以標記逮矛。
4無連接:無連接的含義是限制每次連接只處理一個請求。服務器處理完客戶的請求转砖, 并收到客戶的應答后须鼎,即斷開連接。采用這種方式可以節(jié)省傳輸時間府蔗。
5無狀態(tài):HTTP協(xié)議是無狀態(tài)協(xié)議晋控。無狀態(tài)是指協(xié)議對于事務處理沒有記憶能力。 缺少狀態(tài)意味著如果后續(xù)處理需要前面的信息礁竞,則它必須重傳糖荒,這樣可能導致每 次連接傳送的數(shù)據(jù)量增大。另一方面模捂,在服務器不需要先前信息時它的應答就較快
07Http 1.0 與 Http1.1的區(qū)別
1.0協(xié)議捶朵,客戶端與web服務器建立連接后蜘矢,只能獲得一個web資源! 而1.1協(xié)議综看,允許客戶端與web服務器建立連接后品腹,在一個連接上獲取多個web資源!
2红碑、網(wǎng)絡通信
01舞吭、網(wǎng)絡三要素
IP:主機的唯一表示
端口號:正在運行的程序
協(xié)議:通信規(guī)則,TCP以及UDP
02析珊、網(wǎng)絡模型
ISO模型:
應用層
會話層
表示層
網(wǎng)絡層
傳輸層
數(shù)據(jù)鏈路層
物理層
TCP/IP模型:
應用層
網(wǎng)際層
數(shù)據(jù)層
物理層
03羡鸥、TCP與UDP區(qū)別:
TCP:
建立連接
安全可靠協(xié)議
以流進行數(shù)據(jù)傳遞,無大小限制
三次握手協(xié)議
UDP:
不建立連接
不可靠協(xié)議
以數(shù)據(jù)包傳遞忠寻,有大小限制64K
04惧浴、Socket以及Http:
Socket:長連接
Http:短連接
05、網(wǎng)絡通信中的具體內(nèi)部細節(jié)
URL地址奕剃、IP地址:
http://www.abc.com:80/abc/index.html
http://202.108.22.5/
①客戶端執(zhí)行網(wǎng)絡請求衷旅,從URL中解析出服務器的主機名
②將服務器的主機名轉換成服務器的IP地址 (DNS域名解析)
③從URL中將端口號解析出來
④建立一條客戶端與Web服務器的TCP連接
⑤客戶端通過輸出流向服務器發(fā)送一條Http請求
⑥服務器向客戶端回送一條Http響應報文
⑦客戶端從輸入流獲取報文
⑧客戶端解析報文,關閉連接
⑨客戶端將結果顯示在UI上
3纵朋、異步和同步的區(qū)別
同步:就是在發(fā)出一個功能調(diào)用時柿顶,在沒有得到結果之前,該調(diào)用就不返回操软。也就是必須一件一件事做,等前一件做完了才能做下一件事嘁锯;
異步:當一個異步過程調(diào)用發(fā)出后,調(diào)用者不能立刻得到結果寺鸥。實際處理這個調(diào)用的部件在完成后猪钮,通過狀態(tài)、通知和回調(diào)來通知調(diào)用者胆建;
同步是阻塞模式烤低,異步是非阻塞模式
同步是指:發(fā)送方發(fā)出數(shù)據(jù)后,等接收方發(fā)回響應以后才發(fā)下一個數(shù)據(jù)包的通訊方式笆载。
異步是指:發(fā)送方發(fā)出數(shù)據(jù)后扑馁,不等接收方發(fā)回響應,接著發(fā)送下個數(shù)據(jù)包的通訊方式
4凉驻、HttpURlconnection發(fā)送網(wǎng)絡請求:
01,get請求
//子線程中執(zhí)行請求
URL url = new URL(path);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setConnectTimeout(5000);
if (urlConnection.getResponseCode() == 200){
InputStream inputStream = urlConnection.getInputStream();
}
02,post請求
//子線程中執(zhí)行請求
URL url = new URL(path);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("POST");
urlConnection.setConnectTimeout(5000);
urlConnection.setReadTimeout(5000);
String content = "name="+URLEncoder.encode(name)+"&pass="+URLEncoder.encode(pass);//數(shù)據(jù)編解碼
urlConnection.setRequestProperty("Content-Type","application/x-www-form-urlencoded");//設置請求頭
urlConnection.setRequestProperty("Content-Length",content.length()+"");
urlConnection.setDoOutput(true);
OutputStream outputStream = urlConnection.getOutputStream();
outputStream.write(content.getBytes());
if (urlConnection.getResponseCode() == 200){ }
03,json解析:
json解析
bean:
JSONObject jsonObject = new JSONObject(text);
String code = jsonObject.getString("resultCode");
array:
ArrayList<StuClzInfo> list = new ArrayList<>();
JSONArray array = new JSONArray(text);
for (int i = 0; i < array.length(); i++) {
StuClzInfo info = new StuClzInfo();
JSONObject object = array.getJSONObject(i);
info.setCode(object.getString("code"));
info.setCount(object.getInt("count"));
list.add(info);
}
bean中帶array:
JSONObject object = new JSONObject(text);
String resultCode = object.getString("resultCode");
if ("1".equals(resultCode)) {
tv_name.setText(object.getString("school"));
JSONArray clazz = object.getJSONArray("clazz");
List<StuClzInfo> list = new ArrayList<>();
for (int i = 0; i < clazz.length(); i++) {
JSONObject o = clazz.getJSONObject(i);
StuClzInfo info = new StuClzInfo();
info.setCode(o.getString("code"));
info.setCount(o.getInt("count"));
list.add(info);
}
}
gson解析(bean,array,bean中帶array)
bean:
Gson gson = new Gson();
LoginInfo loginInfo = gson.fromJson(text, LoginInfo.class);//bean
array:
Gson gson = new Gson();
Type type = new TypeToken<List<StuClzInfo>>() {}.getType();
List<StuClzInfo> list = gson.fromJson(text, type);//list<bean>
bean中帶array:
SchoolInfo info = gson.fromJson(text, SchoolInfo.class);
list = info.getClazz();//bean.list<bean>
fastjson解析(bean,array,bean中帶array)
bean:
LoginInfo loginInfo1 = JSON.parseObject(text, LoginInfo.class);
array:
List<StuClzInfo> list = JSON.parseArray(text, StuClzInfo.class);
bean中帶array:
SchoolInfo info = JSON.parseObject(text, SchoolInfo.class);
List<StuClzInfo> list = info.getClazz();
5,OkHttp3講解
01,OkHttp3簡介
> 1.支持http和https協(xié)議,api相同,易用;
2.http使用線程池,https使用多路復用;
3.okhttp支持同步和異步調(diào)用;
4.支持普通form和文件上傳form;
5.操作請求和響應(日志,請求頭,body等);
6.okhttp可以設置緩存;
7.支持透明的gzip壓縮響應體
02,OkHttp3 配置
> 1,Android Studio 配置gradle:
implementation 'com.squareup.okhttp3:okhttp:3.12.0'
2,添加網(wǎng)絡權限:
<uses-permission android:name="android.permission.INTERNET"/>
03腻要,OkHttp3 使用思路
get請求思路
1.獲取okHttpClient對象
2.構建Request對象
3.構建Call對象
4.通過Call.enqueue(callback)方法來提交異步請求;execute()方法實現(xiàn)同步請求
post請求思路
1.獲取okHttpClient對象
2.創(chuàng)建RequestBody
3.構建Request對象
4.構建Call對象
5.通過Call.enqueue(callback)方法來提交異步請求涝登;execute()方法實現(xiàn)同步請求
04雄家,OkHttp3 發(fā)送異步請求(GET)
String url = "http://";
//第一步獲取okHttpClient對象
OkHttpClient client = new OkHttpClient.Builder()
.build();
//第二步構建Request對象
Request request = new Request.Builder()
.url(url)
.get()
.build();
//第三步構建Call對象
Call call = client.newCall(request);
//第四步:異步get請求
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.i("onFailure", e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String result = response.body().string();
Log.i("result", result);
}
});
04,OkHttp3 發(fā)送同步請求(GET)
String url = "http://";
//第一步獲取okHttpClient對象
OkHttpClient client = new OkHttpClient.Builder()
.build();
//第二步構建Request對象
Request request = new Request.Builder()
.url(url)
.get()
.build();
//第三步構建Call對象
final Call call = client.newCall(request);
//第四步:同步get請求
new Thread(new Runnable() {
@Override
public void run() {
try {
Response response = call.execute();//必須子線程執(zhí)行
String result = response.body().string();
Log.i("response", result);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
05胀滚,OkHttp3 發(fā)送異步請求(POST)
//接口參數(shù) String username,String password
String url = "http://";
//第一步創(chuàng)建OKHttpClient
OkHttpClient client = new OkHttpClient.Builder()
.build();
//第二步創(chuàng)建RequestBody(Form表達)
RequestBody body = new FormBody.Builder()
.add("username", "admin")
.add("password", "123456")
.build();
//第三步創(chuàng)建Rquest
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
//第四步創(chuàng)建call回調(diào)對象
final Call call = client.newCall(request);
//第五步發(fā)起請求
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.i("onFailure", e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String result = response.body().string();
Log.i("result", result);
}
});
05趟济,OkHttp3 發(fā)送同步請求(POST)
//接口參數(shù) String username,String password
String url = "http://";
//第一步創(chuàng)建OKHttpClient
OkHttpClient client = new OkHttpClient.Builder()
.build();
//第二步創(chuàng)建RequestBody
RequestBody body = new FormBody.Builder()
.add("username", "admin")
.add("password", "123456")
.build();
//第三步創(chuàng)建Rquest
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
//第四步創(chuàng)建call回調(diào)對象
final Call call = client.newCall(request);
//第五步發(fā)起請求
new Thread(new Runnable() {
@Override
public void run() {
try {
Response response = call.execute();
String result = response.body().string();
Log.i("response", result);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
06, 請求頭處理(Header)以及超時和緩沖處理以及響應處理
//超時設置
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(5,TimeUnit.SECONDS)
.readTimeout(5,TimeUnit.SECONDS)
.writeTimeout(5,TimeUnit.SECONDS)
.cache(new Cache(cacheDirectory,10*1024*1024))
.build();
//表單提交
RequestBody requestBody = new FormBody.Builder()
.add("pno", "1")
.add("ps","50")
.add("dtype","son")
.add("key","4a7cf244fd7efbd17ecbf0cb8e4d1c85")
.build();
//請求頭設置
Request request = new Request.Builder()
.url(url)
.addHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8")
.header("User-Agent", "OkHttp Example")
.post(body)
.build();
//響應處理
@Override
public void onResponse(Call call, Response response) throws IOException {
//響應行
Log.d("ok", response.protocol() + " " +response.code() + " " + response.message());
//響應頭
Headers headers = response.headers();
for (int i = 0; i < headers.size(); i++) {
Log.d("ok", headers.name(i) + ":" + headers.value(i));
}
//響應體
final String string = response.body().string();
Log.d("ok", "onResponse: " + string);
runOnUiThread(new Runnable() {
@Override
public void run() {
tx.setText(string);
}
});
}
07, 請求體處理(Form表單乱投,String字符串,流顷编,文件)
//1.POST方式提交String/JSON application/json;json串
MediaType mediaType1 = MediaType.parse("application/x-www-form-urlencoded;charset=utf-8");
String requestBody = "pno=1&ps=50&dtype=son&key=4a7cf244fd7efbd17ecbf0cb8e4d1c85";
RequestBody requestBody1 = RequestBody.create(mediaType1, requestBody);
//POST方式提交JSON:傳遞JSON同時設置son類型頭
RequestBody requestBodyJson = RequestBody.create(MediaType.parse("application/json;charset=utf-8"), "{}");
request.addHeader("Content-Type", "application/json")//必須加json類型頭
//POST方式提交無參
RequestBody requestBody1 = RequestBody.create(MediaType.parse("application/x-www-form-urlencoded;charset=utf-8"), "");
//2.POST方式提交流
RequestBody requestBody2 = new RequestBody() {
@Nullable
@Override
public MediaType contentType() {
return MediaType.parse("application/x-www-form-urlencoded;charset=utf-8");
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
sink.writeUtf8("pno=1&ps=50&dtype=son&key=4a7cf244fd7efbd17ecbf0cb8e4d1c85");
}
};
//3.POST方式提交表單
RequestBody requestBody4 = new FormBody.Builder()
.add("pno", "1")
.add("ps","50")
.add("dtype","son")
.add("key","4a7cf244fd7efbd17ecbf0cb8e4d1c85")
.build();
//4.POST提交文件
MediaType mediaType3 = MediaType.parse("text/x-markdown; charset=utf-8");
File file = new File("test.txt");
RequestBody requestBody3 = RequestBody.create(mediaType3, file);
//5.POST方式提交分塊請求
MultipartBody body = new MultipartBody.Builder("AaB03x")
.setType(MultipartBody.FORM)
.addPart(
Headers.of("Content-Disposition", "form-data; name=\"title\""),
RequestBody.create(null, "Square Logo"))
.addPart(
Headers.of("Content-Disposition", "form-data; name=\"image\""),
RequestBody.create(MediaType.parse("image/png"), new File("website/static/logo-square.png")))
.build();
08, 攔截器:網(wǎng)絡攔截器戚炫,緩存攔截器,日志攔截器媳纬,重定向攔截器
一双肤、Application Intercetor和NetworkInterceptor的區(qū)別
1,Application interceptors 應用攔截器
builder.addInterceptor(new LoggingInterceptor())
Application Interceptor 是第一個 Interceptor 因此它會被第一個執(zhí)行,因此這里的 request 還是最原始的钮惠。而對于 response 而言呢茅糜,因為整個過程是遞歸的調(diào)用過程,因此它會在 CallServerInterceptor 執(zhí)行完畢之后才會將 Response 進行返回萌腿,因此在 Application Interceptor 這里得到的 response 就是最終的響應限匣,雖然中間有重定向抖苦,但是這里只關心最終的 response
1,不需要去關心中發(fā)生的重定向和重試操作毁菱。因為它處于第一個攔截器,會獲取到最終的響應
2,只會被調(diào)用一次锌历,即使這個響應是從緩存中獲取的贮庞。
3,只關注最原始的請求,不去關系請求的資源是否發(fā)生了改變究西,我只關注最后的 response 結果而已窗慎。
4,因為是第一個被執(zhí)行的攔截器,因此它有權決定了是否要調(diào)用其他攔截卤材,也就是 Chain.proceed() 方法是否要被執(zhí)行遮斥。
5,因為是第一個被執(zhí)行的攔截器,因此它有可以多次調(diào)用 Chain.proceed() 方法扇丛,其實也就是相當與重新請求的作用了术吗。
2,Network Interceptors 網(wǎng)絡攔截器
builder.addNetworkInterceptor(new LoggingInterceptor())
NetwrokInterceptor 處于第 6 個攔截器中,它會經(jīng)過 RetryAndFollowIntercptor 進行重定向并且也會通過 BridgeInterceptor 進行 request 請求頭和 響應 resposne 的處理帆精,因此這里可以得到的是更多的信息较屿。在打印結果可以看到它內(nèi)部是發(fā)生了一次重定向操作,在上圖可以看出卓练,為什么 NetworkInterceptor 可以比 Application Interceptor 得到更多的信息了
1,因為 NetworkInterceptor 是排在第 6 個攔截器中隘蝎,因此可以操作經(jīng)過 RetryAndFollowup 進行失敗重試或者重定向之后得到的resposne。
2,對于從緩存獲取的 response 則不會去觸發(fā) NetworkInterceptor 襟企。因為響應直接從 CacheInterceptor 返回了嘱么。
3,觀察數(shù)據(jù)在網(wǎng)絡中的傳輸。
4,可以獲得裝載請求的連接顽悼。
二曼振、攔截器的應用
1.日志攔截器
在 LoggingInterceptor 中主要做了 3 件事:
1,請求前-打印請求信息辉川;
2,網(wǎng)絡請求-遞歸去調(diào)用其他攔截器發(fā)生網(wǎng)絡請求;
3,網(wǎng)絡響應后-打印響應信息
OkHttpClient client = builder
.addInterceptor(new LoggingInterceptor())//應用攔截器
.addNetworkInterceptor(new LoggingInterceptor())//網(wǎng)絡攔截器
.readTimeout(5, TimeUnit.SECONDS)
.connectTimeout(5, TimeUnit.SECONDS)
.writeTimeout(5, TimeUnit.SECONDS)
.build();
class LoggingInterceptor implements Interceptor {
private static final String TAG = "LoggingInterceptor";
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
//1.請求前--打印請求信息
long startTime = System.nanoTime();
Log.d(TAG, String.format("Sending request %s on %s%n%s",
request.url(), chain.connection(), request.headers()));
//2.網(wǎng)絡請求
Response response = chain.proceed(request);
//3.網(wǎng)絡響應后--打印響應信息
long endTime = System.nanoTime();
Log.d(TAG, String.format("Received response for %s in %.1fms%n%s",
response.request().url(), (endTime - startTime) / 1e6d, response.headers()));
return response;
}
}
2.緩存攔截器
在 MyCacheinterceptor 中主要做了(post方式無法緩存)
1,設置緩存位置
2,無網(wǎng)時:設置緩存協(xié)議
3,有網(wǎng):加載網(wǎng)絡數(shù)據(jù)拴测;無網(wǎng):加載緩存數(shù)據(jù)
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(myCacheinterceptor)//應用攔截器
.addNetworkInterceptor(myCacheinterceptor)//網(wǎng)絡攔截器
.connectTimeout(5, TimeUnit.SECONDS)
.cache(new Cache(new File(getCacheDir(), "Cache"), 1024 * 1024 * 10))
.build();
class MyCacheinterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!isNetworkAvailable(MainActivity.this)) {
request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build();
}
Response originalResponse = chain.proceed(request);
if (isNetworkAvailable(MainActivity.this)) {
int maxAge = 0;
return originalResponse.newBuilder()
.removeHeader("Pragma")
.header("Cache-Control", "public ,max-age=" + maxAge)
.build();
} else {
int maxStale = 15*60;
return originalResponse.newBuilder()
.removeHeader("Pragma")
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.build();
}
}
}
/**
檢測是否有網(wǎng)
*/
public static boolean isNetworkAvailable(Context context) {
if (context != null) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = cm.getActiveNetworkInfo();
if (info != null) {
return info.isAvailable();
}
}
return false;
}
09注意事項
1乓旗,推薦讓 OkHttpClient 保持單例,用同一個 OkHttpClient 實例來執(zhí)行你的所有請求集索,因為每一個 OkHttpClient 實例都擁有自己的連接池和線程池屿愚,重用這些資源可以減少延時和節(jié)省資源,如果為每個請求創(chuàng)建一個 OkHttpClient 實例务荆,顯然就是一種資源的浪費妆距。
2,response.body().string()只調(diào)用一次
3函匕,每一個Call(其實現(xiàn)是RealCall)只能執(zhí)行一次娱据,否則會報異常
4,子線程加載數(shù)據(jù)后盅惜,主線程刷新數(shù)據(jù)
10,HttpURLconnection及OkHttp3的對比分析
1,HttpUrlConnection中剩,google官方提供的用來訪問網(wǎng)絡,但是實現(xiàn)的比較簡單抒寂,只支持1.0/1.1
2,并沒有多路復用结啼,如果碰到app大量網(wǎng)絡請求的時候,性能比較差屈芜,
3,HttpUrlConnection底層也是用Socket來實現(xiàn)的
4,OkHttp像HttpUrlConnection一樣郊愧,實現(xiàn)了一個網(wǎng)絡連接的過程。
5,OkHttp和HttpUrlConnection是一級的井佑,用socket實現(xiàn)了網(wǎng)絡連接属铁,OkHttp更強大,
6,HttpUrlConnection在IO方面用到的是InputStream和OutputStream躬翁,但OkHttp用的是sink和source焦蘑,這兩個是在Okio這個開源庫里的, feredSink(支持緩沖)姆另、GzipSink(支持Gzip壓縮)喇肋、ForwardingSink和InflaterSink(后面這兩者服務于GzipSink)
7,多個相同host和port的stream可以共同使用一個socket,而RealConnection就是處理連接的迹辐,那也就是說一個RealConnection上可能有很多個Stream
8蝶防,OkHttp代碼比HttpURLConnection精簡的多
11,OkHttp源碼分析(設計模式,線程池的使用)
4.單利明吩、多線程安全問題
/**
餓漢式
*/
public class Person {
//1.構造函數(shù)私有化
private Person(){}
//2.創(chuàng)建單個私有對象對象
private static Person person = new Person();
//3.提供對外公開訪問方法
public static Person getPerson() {
return person;
}
}
/**
* 懶漢式
*
* 多線程安全問題:
* 1.多個線程同時操作
* 2.共用同一個資源
* 3.分步執(zhí)行操作同一個資源
*
* 多線程安全解決方式:
* 1.同步方法
* 2.同步代碼塊
* 3.鎖機制
*/
public class Student {
//1.構造函數(shù)私有化
private Student(){}
//2.創(chuàng)建單個私有對象對象
private static Student student;
//3.提供對外公開訪問方法
public static Student getInstance(){
//解決線程安全問題
if (student == null){
synchronized (Student.class){
if (student == null) {
student = new Student();
}
}
}
return student;
}
}
5.OkHttpUtils工具類抽取
public class OkHttpUtils {
private static OkHttpUtils okHttpUtils;
private static OkHttpClient okHttpClient;
private static Handler mHandler;
/**
* 構造初始化
*/
private OkHttpUtils(){
/**
* 構建OkHttpClient
*/
okHttpClient = new OkHttpClient.Builder()
/**
* 請求的超時時間
*/
.readTimeout(5000, TimeUnit.MILLISECONDS)
/**
* 設置響應的超時時間
*/
.writeTimeout(5000, TimeUnit.MILLISECONDS)
/**
* 設置連接的超時時間
*/
.connectTimeout(5000, TimeUnit.MILLISECONDS)
/**
* 構建
*/
.build();
/**
* 獲取主線程的handler
*/
mHandler = new Handler(Looper.getMainLooper());
}
/**
* 通過單例模式構造對象
* @return
*/
public static OkHttpUtils getInstance(){
if (OkHttpUtils == null){
synchronized (OkHttpUtils.class){
if (okHttpUtils == null){
okHttpUtils = new OkHttpUtils();
}
}
}
return okHttpUtils;
}
/**
* 構造Get請求间学,封裝對用的Request請求,實現(xiàn)方法
* @param url 訪問路徑
* @param realCallback 接口回調(diào)
*/
private void getRequest(String url, final RealCallback realCallback){
Request request = new Request.Builder().url(url).get().build();
deliveryResult(realCallback, okHttpClient.newCall(request));
}
/**
* 構造post 請求,封裝對用的Request請求低葫,實現(xiàn)方法
* @param url 請求的url
* @param requestBody 請求參數(shù)
* @param realCallback 結果回調(diào)的方法
*/
private void postRequest(String url, RequestBody requestBody, final RealCallback realCallback){
Request request = new Request.Builder().url(url).post(requestBody).build();
deliveryResult(realCallback, okHttpClient.newCall(request));
}
/**
* 處理請求結果的回調(diào):主線程切換
* @param realCallback
* @param call
*/
private void deliveryResult(final RealCallback realCallback, Call call) {
call.enqueue(new Callback() {
@Override
public void onFailure(final Call call, final IOException e) {
sendFailureThread(call, e, realCallback);
}
@Override
public void onResponse(final Call call, final Response response) throws IOException {
sendSuccessThread(call, response, realCallback);
}
});
}
/**
* 發(fā)送成功的回調(diào)
* @param call
* @param response
* @param realCallback
*/
private void sendSuccessThread(final Call call, final Response response, final RealCallback
realCallback) {
mHandler.post(new Runnable() {
@Override
public void run() {
realCallback.onResponse(call,response);
}
});
}
/**
* 發(fā)送失敗的回調(diào)
* @param call
* @param e
* @param realCallback
*/
private void sendFailureThread(final Call call, final IOException e, final RealCallback realCallback) {
mHandler.post(new Runnable() {
@Override
public void run() {
realCallback.onFailure(call,e);
}
});
}
//-----------對外公共訪問的get/post方法-----------
/**
* get請求
* @param url 請求url
* @param realCallback 請求回調(diào)
*/
public void get(String url, final RealCallback realCallback){
getRequest(url,realCallback);
}
/**
* post請求
* @param url 請求url
* @param realCallback 請求回調(diào)
* @param requestBody 請求參數(shù)
*/
public void post(String url, RequestBody requestBody, final RealCallback realCallback){
postRequest(url,requestBody,realCallback);
}
/**
* http請求回調(diào)類,回調(diào)方法在UI線程中執(zhí)行
*/
public static abstract class RealCallback {
/**
* 請求成功回調(diào)
* @param response
*/
public abstract void onResponse(Call call,Response response);
/**
* 請求失敗回調(diào)
* @param e
*/
public abstract void onFailure(Call call,IOException e);
}
}