前言
Android網(wǎng)絡(luò)技術(shù)
- android原生的使用http訪問(wèn)網(wǎng)絡(luò)【HttpUrlConnection削饵、HttpClient】
官方推薦使用:HttpUrlConnection
而對(duì)于HttpClient,6.0已經(jīng)廢除:HttpClient,api過(guò)多未巫,擴(kuò)展困難窿撬,難以維護(hù) - android-async-http。與volley一樣是異步網(wǎng)絡(luò)庫(kù)叙凡,但volley是封裝的httpUrlConnection劈伴,它是封裝的httpClient,而android平臺(tái)不推薦用HttpClient了握爷,所以這個(gè)庫(kù)已經(jīng)不適合android平臺(tái)了跛璧。
- volley 非常適合去進(jìn)行數(shù)據(jù)量不大严里,但通信頻繁的網(wǎng)絡(luò)操作。不適合下載問(wèn)價(jià)一類(之前寫的關(guān)于新聞資訊的demo 用的就是volley網(wǎng)絡(luò)請(qǐng)求追城。請(qǐng)求頻繁刹碾,像流星)
- 但是在開(kāi)元盛行的今天,有許多出色的網(wǎng)絡(luò)通信庫(kù)都可以代替原生的HttpUrlConnection
- okthttp應(yīng)該是最出色的一個(gè)座柱,由square公司開(kāi)發(fā)迷帜,在接口封裝上做的簡(jiǎn)單易用,底層實(shí)現(xiàn)也是自成一派色洞,現(xiàn)在已經(jīng)成了廣大android開(kāi)發(fā)者首選的網(wǎng)絡(luò)通信庫(kù)戏锹。從Android4.4開(kāi)始HttpURLConnection的底層實(shí)現(xiàn)采用的是okHttp。
- Retrofit也是square公司的锋玲, 速度快景用、傳輸層默認(rèn)使用okhttp涵叮、如果程序中集成了okhttp惭蹂、Retrofit默認(rèn)會(huì)使用OKHttp處理其他網(wǎng)絡(luò)層請(qǐng)求。Retrofit官網(wǎng)地址
這篇文章主要講okhttp的基礎(chǔ)使用
官網(wǎng)okhttp找到最新版本割粮,gradle中引入依賴
compile 'com.squareup.okhttp3:okhttp:3.9.0'
okhttp內(nèi)部依賴okio,所以在okio-github地址找到最新版本
compile 'com.squareup.okio:okio:1.13.0'
最后記得加入網(wǎng)絡(luò)權(quán)限
<uses-permission android:name="android.permission.INTERNET"/>
大綱
-
GET請(qǐng)求
-
POST請(qǐng)求
-
RequestBody--json數(shù)據(jù)提交
-
FormBody--表單數(shù)據(jù)提交
-
MultipartBody--文件上傳
-
一盾碗、Get請(qǐng)求
一個(gè)最簡(jiǎn)單的使用okhttp進(jìn)行網(wǎng)絡(luò)請(qǐng)求的例子,get獲取訪問(wèn)網(wǎng)頁(yè)的內(nèi)容舀瓢,返回的即是這個(gè)網(wǎng)頁(yè)的html廷雅,將內(nèi)容顯示出來(lái)
//主要代碼
private void sendGetRuquestWithOkHttp() {
//創(chuàng)建okHttpClient對(duì)象
OkHttpClient okHttpClient=new OkHttpClient();
//創(chuàng)建request,首先要有一個(gè)url
Request request=new Request.Builder().url(netUrl).build();
//通過(guò)request的對(duì)象去構(gòu)造得到一個(gè)Call對(duì)象,
// 類似于將你的請(qǐng)求封裝成了任務(wù)京髓,既然是任務(wù)航缀,就會(huì)有execute()和cancel()等方法。
Call call=okHttpClient.newCall(request);
//以異步的方式去執(zhí)行請(qǐng)求,調(diào)用的是call.enqueue堰怨,將call加入調(diào)度隊(duì)列芥玉,
// 然后等待任務(wù)執(zhí)行完成,我們?cè)贑allback中即可得到結(jié)果备图。
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//請(qǐng)求失敗的處理
}
@Override
public void onResponse(Call call, Response response) throws IOException {
//請(qǐng)求成功返回結(jié)果
//如果希望返回的是字符串
final String responseData=response.body().string();
//如果希望返回的是二進(jìn)制字節(jié)數(shù)組
byte[] responseBytes=response.body().bytes();
//如果希望返回的是inputStream,有inputStream我們就可以通過(guò)IO的方式寫文件.
InputStream responseStream=response.body().byteStream();
//注意灿巧,此時(shí)的線程不是ui線程,
// 如果此時(shí)我們要用返回的數(shù)據(jù)進(jìn)行ui更新揽涮,操作控件抠藕,就要使用相關(guān)方法
runOnUiThread(new Runnable() {
@Override
public void run() {
// 更新UI的操作
textView.setText(responseData);
}
});
}
});
//上面用到的enqueue是異步的方式,當(dāng)然也可以同步蒋困,
//同步--Call有一個(gè)execute()方法盾似,你也可以直接調(diào)用call.execute()通過(guò)返回一個(gè)Response。
/* try {
Response response = call.execute();
if(response.isSuccessful()){
//同步方式下得到返回結(jié)果
String responseByExecute=response.body().string();
}
} catch (IOException e) {
e.printStackTrace();
}*/
}
在上面的代碼中:sendRuquestWithOkHttp()方法為網(wǎng)絡(luò)請(qǐng)求的主要代碼
- 創(chuàng)建okHttpClient對(duì)象
- 創(chuàng)建Request對(duì)象
- 把請(qǐng)求封裝成任務(wù)雪标,得到Call對(duì)象
- 以同步或異步的方法去執(zhí)行請(qǐng)求零院,將call加入調(diào)度隊(duì)列购岗,任務(wù)執(zhí)行完成,在CallBack中得到回調(diào)(異步)门粪。同步通過(guò)call.execute().body().string();得到返回結(jié)果
關(guān)于同步和異步
- 同步調(diào)用喊积,在發(fā)起一個(gè)函數(shù)或方法調(diào)用時(shí),沒(méi)有得到結(jié)果之前玄妈,該調(diào)用就不返回乾吻,直到返回結(jié)果;同步就是發(fā)出一個(gè)請(qǐng)求后什么事都不做拟蜻,一直等待請(qǐng)求返回后才會(huì)繼續(xù)做事绎签;
- 異步調(diào)用的概念和同步相對(duì),在一個(gè)異步調(diào)用發(fā)起后酝锅,被調(diào)用者立即返回給調(diào)用者诡必,但調(diào)用者不能立刻得到結(jié)果,被調(diào)用者在實(shí)際處理這個(gè)調(diào)用的請(qǐng)求完成后搔扁,通過(guò)狀態(tài)爸舒、通知或回調(diào)等方式來(lái)通知調(diào)用者請(qǐng)求處理的結(jié)果。異步就是發(fā)出請(qǐng)求后繼續(xù)去做其他事稿蹲,這個(gè)請(qǐng)求處理完成后會(huì)通知你扭勉,這時(shí)候就可以處理這個(gè)回應(yīng)了
用一個(gè)例子來(lái)形容:
- 在同步環(huán)境下,客戶端叫服務(wù)端去吃飯苛聘,服務(wù)端沒(méi)聽(tīng)見(jiàn)或是沒(méi)有回答客戶端涂炎,客戶端就一直叫,直到服務(wù)端說(shuō)聽(tīng)到了设哗,它們才一起去吃飯唱捣。
- 在異步環(huán)境下,客戶端叫服務(wù)端去吃飯网梢,客戶端也不等服務(wù)端震缭,自己就先去吃了,因?yàn)榭蛻舳艘埠苊ε焖冢凶约旱氖虑橹颍荒芤恢钡戎兑膊蛔觯?wù)端知道了之后活烙,可能馬上就去吃飯徐裸,也可能忙完手頭的事情才去吃飯。
二啸盏、POST請(qǐng)求
post和get的不同在于對(duì)Request請(qǐng)求的構(gòu)造不同(因?yàn)閜ost需要攜帶參數(shù))重贺,post方式中的Request需要傳遞一個(gè)RequestBody作為post的參數(shù)。RequestBody有兩個(gè)子類:FormBody和MultipartBody
-
RequestBody--json數(shù)據(jù)提交
public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
OkHttpClient client = new OkHttpClient();
String post(String url, String json) throws IOException {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
//同步
Response response = client.newCall(request).execute();
f (response.isSuccessful()) {
return response.body().string();
} else {
throw new IOException("Unexpected code " + response);
}
}
-
FromBody---表單提交 這種能滿足大部分的需求
FromBody用于提交表單鍵值對(duì),key-value,其作用類似于HTML中的<form>標(biāo)記。比如username="LHX",age="21"等類似的鍵值對(duì)
我們可以使用HashMap<String气笙,String>這樣的數(shù)據(jù)結(jié)構(gòu)來(lái)存儲(chǔ)接口所需參數(shù)的鍵值對(duì)次企,它的查找速度為O(1),很快,但是對(duì)于API接口參數(shù)來(lái)說(shuō)潜圃,數(shù)據(jù)不會(huì)太多缸棵,查找快體現(xiàn)不出優(yōu)勢(shì)來(lái),并且HashMap比較耗費(fèi)內(nèi)存谭期。以下是使用hashmap的例子:
private void fetchDataByPost() {
//把參數(shù)傳進(jìn)Map中
HashMap<String,String> paramsMap=new HashMap<>();
paramsMap.put("name","哈哈");
paramsMap.put("client","Android");
paramsMap.put("id","3243598");
FormBody.Builder builder = new FormBody.Builder();
for (String key : paramsMap.keySet()) {
//追加表單信息
builder.add(key, paramsMap.get(key));
}
OkHttpClient okHttpClient=new OkHttpClient();
RequestBody formBody=builder.build();
Request request=new Request.Builder().url(netUrl).post(formBody).build();
Call call=okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//請(qǐng)求失敗的處理
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
}
所以我們還有一種方式可以裝取鍵值對(duì)堵第,通過(guò)ArrayList<RequestParameter>這樣的數(shù)據(jù)結(jié)構(gòu)。
//首先要有一個(gè)RequestParameter類
public class RequestParameter implements Serializable {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
private String name;
private String value;
public RequestParameter(String name,String value){
this.name=name;
this.value=value;
}
}
List<RequestParameter> parameter=new ArrayList<>();
RequestParameter rp1=new RequestParameter("name","哈哈");
parameter.add(rp1);
RequestParameter rp2=new RequestParameter("client","Android");
parameter.add(rp2);
//創(chuàng)建一個(gè)FormBody.Builder
FormBody.Builder builder=new FormBody.Builder();
if (parameter!=null&¶meter.size()>0){
for (final RequestParameter p : parameter) {
builder.add(p.getName(),p.getValue());
}
}
RequestBody formBody=builder.build();
OkHttpClient okHttpClient=new OkHttpClient();
Request request=new Request.Builder().url(netUrl).post(formBody).build();
Call call=okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//請(qǐng)求失敗的處理
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
-
MultipartBody---文件上傳
MultipartBody可以構(gòu)建與HTML文件上傳格式兼容的復(fù)雜請(qǐng)求體隧出。
File file=new File(Environment.getExternalStorageDirectory(), "balabala.png");
MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
RequestBody filebody = MultipartBody.create(MEDIA_TYPE_PNG, file);
MultipartBody.Builder multiBuilder=new MultipartBody.Builder();
//這里是 封裝上傳圖片參數(shù)
multiBuilder.addFormDataPart("file", file.getName(), filebody);
//參數(shù)以添加header方式將參數(shù)封裝踏志,否則上傳參數(shù)為空
// 設(shè)置請(qǐng)求體
multiBuilder.setType(MultipartBody.FORM);
//這里是 封裝上傳圖片參數(shù)
multiBuilder.addFormDataPart("file", file.getName(), filebody);
// 封裝請(qǐng)求參數(shù),這里最重要
HashMap<String, String> params = new HashMap<>();
params.put("client","Android");
params.put("uid","1061");
params.put("token","1911173227afe098143caf4d315a436d");
params.put("uuid","A000005566DA77");
//參數(shù)以添加header方式將參數(shù)封裝,否則上傳參數(shù)為空
if (params != null && !params.isEmpty()) {
for (String key : params.keySet()) {
multiBuilder.addPart(
Headers.of("Content-Disposition", "form-data; name=\"" + key + "\""),
RequestBody.create(null, params.get(key)));
}
}
RequestBody multiBody=multiBuilder.build();
OkHttpClient okHttpClient=new OkHttpClient();
Request request=new Request.Builder().url(netUrl).post(multiBody).build();
Call call=okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//請(qǐng)求失敗的處理
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
圖片下載胀瞪,文件下載
圖片下載是通過(guò)回調(diào)的Response拿到byte[]然后decode成圖片针余;
文件下載,就是拿到inputStream做寫文件操作凄诞;