這篇文章主要總結Android著名網絡框架-okhttp的基礎使用。 okhttp是什麼 okhttp是Android端的一個Http客戶端,其基礎功能至關於Android自帶的HttpURLConnection和Apache HTTP Client,但他卻比自帶的2個Http客戶端優越不少,一者是寫法簡單,兩者okhttp處理不少網絡複雜問題,如會從不少經常使用的鏈接問題中自動恢復。若是您的服務器配置了多個IP地址,當第一個IP鏈接失敗的時候,OkHttp會自動嘗試下一個IP。OkHttp還處理了代理服務器問題和SSL握手失敗等等不少問題。關於第兩者,這篇文章不討論。html
okhttp的導入java
Gradle導入android
compile'com.squareup.okhttp3:okhttp:3.2.0'web
compile'com.squareup.okio:okio:1.6.0'chrome
okhttp基礎使用json
這裏咱們主要介紹簡單的使用,介紹內容以下api
1.get請求數組
2.post請求,參數是鍵值對服務器
3.post請求,多種類型的body微信
4.文件下載
5.加入Gson
get請求
get請求分爲同步get和異步get,二者的區別主要get的方式是工做在另外一個線程仍是工做在本線程。請求的方式大同小異。
首先定義一個OkHttpClient對象,以下
privateOkHttpClient client
=newOkHttpClient();
而後構建一個Request,構建方式以下:
Requestrequest = newRequest.Builder().
url("http://www.baidu.com").
build();
這個是最簡單的request的構建方式,固然咱們能夠構建的很複雜。
Requestrequest = newRequest.Builder().
url("http://www.baidu.com").
addHeader("User-Agent","android").
header("Content-Type","text/html;
charset=utf-8").
build();
經過addHeader和header方法爲請求增長請求頭部,注意使用header(name, value)能夠設置惟一的name、value。若是已經有值,舊的將被移除,而後添加新的。使用addHeader(name, value)能夠添加多值(添加,不移除已有的)。
同步的get方法,經過client.newCall(request).execute()方法獲得請求的response.
Responseresponse = okHttpClient.newCall(request).execute();
OkHttp封裝了不少處理response的方法,好比response.headers()的獲得headers.
Headers headers = response.headers();
for(inti=0;i< headers.size();i++) {
System.out.println(headers.name(i) +
": " + headers.value(i)); }
結果以下:
Date:Mon,18Apr201605:23:43GMT
Content-Type:text/html; charset=utf-8
Transfer-Encoding:chunked
Connection:Keep-Alive
Vary:Accept-Encoding
Set-Cookie:BAIDUID=A323EC9BF678C0EB78E20741FD71211B:FG=1; expires=Thu,31-Dec-3723:55:55GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie:BIDUPSID=A323EC9BF678C0EB78E20741FD71211B; expires=Thu,31-Dec-3723:55:55GMT; max-age=2147483647;path=/; domain=.baidu.com
Set-Cookie:PSTM=1460957023; expires=Thu,31-Dec-3723:55:55GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie:BDSVRTM=0; path=/
Set-Cookie:BD_HOME=0; path=/
Set-Cookie:H_PS_PSSID=1434_19672_18281_19690_17948_18205_19558_15952_12257;path=/; domain=.baidu.com
P3P:CP=" OTI DSP COR IVA OUR IND COM "
Cache-Control:private
Cxy_all:baidu+2db7793e0e32b9f6c20be8f623e1ae43
Expires:Mon,18Apr201605:22:55GMT
X-Powered-By:HPHP
Server:BWS/1.1
X-UA-Compatible:IE=Edge,chrome=1
BDPAGETYPE:1
BDQID:0xfacc6fc10004ca96
BDUSERID:0
OkHttp-Sent-Millis:1460957021226
OkHttp-Received-Millis:1460957021430
響應報文的實體能夠經過response.body().string()獲取;若是但願得到返回的二進制字節數組,則調用response.body().bytes();若是你想拿到返回的inputStream,則調用response.body().byteStream()。
異步的get請求獲得的response方法是經過以下方法
okHttpClient.newCall(request).enqueue(newCallback() {
@Override
publicvoidonFailure(Call
call, IOException e){
}
@Override
publicvoidonResponse(Call
call, Response response)throwsIOException{
}
});
在onResponse方法中,執行請求成功的代碼,onFailure方法中,執行請求失敗的代碼,下面給一個完整的異步get的栗子
importandroid.os.Bundle;
importandroid.os.Handler;
importandroid.support.v7.app.AppCompatActivity;
importandroid.text.method.ScrollingMovementMethod;
importandroid.widget.TextView;
importjava.io.IOException;
importokhttp3.Call;
importokhttp3.Callback;
importokhttp3.Headers;
importokhttp3.OkHttpClient;
importokhttp3.Request;
importokhttp3.Response;
publicclassMainActivityextendsAppCompatActivity{
privateOkHttpClient
okHttpClient =newOkHttpClient();
publicTextView show;
publicHandler handler =newHandler();
@Override
protectedvoidonCreate(Bundle
savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
show = (TextView) findViewById(R.id.show);
show.setMovementMethod(ScrollingMovementMethod.getInstance());
Request request =newRequest.Builder().
url("http://www.baidu.com").
addHeader("User-Agent","android").
header("Content-Type","text/html;
charset=utf-8").
get().
build();
okHttpClient.newCall(request).enqueue(newCallback() {
@Override
publicvoidonFailure(Call call, IOException e){
}
@Override
publicvoidonResponse(Call call,finalResponse response)throwsIOException{
finalHeaders headers = response.headers();
finalString str =response.body().string();
handler.post(newRunnable() {
@Override
publicvoidrun(){
for(inti =0; i
show.append(headers.name(i) +": "+ headers.value(i));
show.append(str);
}
}
});
}
});
}
}
其實按照官網說的,回調是發生在response的headers準備好就發生的,因此有時候請求response的實體部分會發生阻塞。
post請求——鍵值對爲參數。
post請求和get請求除了在構建request上面不一樣之外,在處理response上面都是同樣的,因此下面咱們只討論一下post構建request,固然post也是支持同步post和異步post的,能夠參考get方法。
在構建post的request時候,首先用FormBody.Builder去構建request的body部分,栗子以下,固然這是OKHttp3的方法.
FormBody.Builder builder =newFormBody.Builder();
for(inti =0; i < key.size() ;i ++){
builder.add(key.get(i),value.get(i));
}
RequestBody body = builder.build();
builder中add的是要加入的參數鍵值對。獲得要構造的body後用
Request request =newRequest.Builder().url(url).post(body).build();
得到請求的request,後面的操做就和get方法是同樣的,這裏能夠參考異步get的栗子,構建一個post的request.下面的寫法原封不變。
post請求--多種類型的body
上文已經說了post和get的用法主要在構建不一樣的request上面,因此接下來咱們主要討論的也是如何構建request.
參考上面,咱們首先要建立一個requestBody,咱們能夠用下面的方式去構建,固然這也是okhttp3的方法
MultipartBody.Builder builder =newMultipartBody.Builder().setType(MultipartBody.FORM);
已表單上傳的形式去提交post。咱們看一下builder的方法
/** Add a part to the body. */
publicBuilderaddPart(RequestBody body){
returnaddPart(Part.create(body));
}
/** Add a part to the body. */
publicBuilderaddPart(Headers headers, RequestBody body){
returnaddPart(Part.create(headers, body));
}
/** Add a form data part to the body. */
publicBuilderaddFormDataPart(String name, Stringvalue){
returnaddPart(Part.createFormData(name,value));
}
/** Add a form data part to the body. */
publicBuilderaddFormDataPart(String name, String filename, RequestBody body){
returnaddPart(Part.createFormData(name, filename, body));
}
從這裏咱們能夠看出能夠直接用public Builder addFormDataPart(String name, String filename,
RequestBody body)上傳一個File,最後一個參數是請求的實體,能夠經過RequestBody.create(final MediaType contentType, final File
file)得到,而MediaType則能夠經過下面方法得到
//調用judgeType方法
privatestaticfinal MediaType
MEDIA_TYPE = MediaType.parse(judgeType(fileName);
//judge方法以下
privateStringjudgeType(Stringpath) {
FileNameMap fileNameMap = URLConnection.getFileNameMap();
StringcontentTypeFor = fileNameMap.getContentTypeFor(path);
if(contentTypeFor ==null) {
contentTypeFor ="application/octet-stream";
}
returncontentTypeFor;
}
因爲我後臺能力比較渣,這裏用一個官網的例子來實現一遍我剛纔討論的方法。
MultipartBody.Builder builder =newMultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("image","logo-square.png",
RequestBody.create(MEDIA_TYPE_PNG,newFile("website/static/logo-square.png")));
RequestBody requestBody = builder.build();
Request request =newRequest.Builder()
.header("Authorization","Client-ID
"+"9199fdef135c122")
.url("https://api.imgur.com/3/image")
.post(requestBody)
.build();
固然除了這個方法之外,調用以下方法也是能夠的,咱們能夠利用name和filename本身構造Header傳上去。
publicBuilderaddPart(Headers headers, RequestBody body){
returnaddPart(Part.create(headers, body))
栗子以下:
builder.addPart(Headers.of("Content-Disposition","form-data; name="" +
name + ""; filename="" + fileName + """),fileBody);
後面的寫法和上面相似,這樣咱們就實現了文件上傳的寫法。
文件下載
剛纔咱們上面已經說了,但願得到返回的二進制字節數組,則調用response.body().bytes();若是你想拿到返回的inputStream,則調用response.body().byteStream()。換句話說,文件的下載能夠簡單的經過get請求,獲得相應的response,在把他的實體轉換成二進制流寫入文件,就是實現了文件的下載。主要的寫法就是文件的讀寫,跟OKHttp關係不大,固然咱們也能夠用okio來實現文件的讀寫,這裏水平有限就不介紹了。下面給一個簡單的例子。
privatevoid_download(finalString url,finalString destFileDir,finalResultCallback callback){
finalRequest request =newRequest.Builder().url(url).build();
finalCall call = okHttpClient.newCall(request);
call.enqueue(newCallback() {
@Override
publicvoidonFailure(Call call, IOException e){
}
@Override
publicvoidonResponse(Call call, Response response)throwsIOException{
InputStream is =null;
byte[] buf =newbyte[2048];
intlen =0;
FileOutputStream fos =null;
try{
is =response.body().byteStream();
File file =newFile(destFileDir,getFileName(url));
fos =newFileOutputStream(file);
while((len = is.read(buf)) != -1){
fos.write(buf,0,len);
}
fos.flush();
//....省略後續對已經保存的文件的操做
}catch(IOException e) {
e.printStackTrace();
}finally{
try{
if(is !=null) is.close();
}catch(IOException e) {
}
try
{
if(fos !=null) fos.close();
}catch(IOException e)
{
}
}
}
});
}
加入Gson
接下來,咱們討論一個很實際的問題,Android的網絡請求通常不會去請求一個網站的Html,更多的是請求後臺接口的Json文件,因此咱們用Gson來處理json的解析。這一部分和前面就不一樣了,前面多數講的是如何構建不一樣的request來獲得response,而對響應的結果,處理都是一致的。但這裏主要的寫法就是用Gson去處理response,而request的構建則根據上面介紹的方法去構建,無需改變。
Gson的導入
compile'com.google.code.gson:gson:2.6.2'
好比咱們後臺給出的api是這樣一個json文件
{
"status":0,
"intro":"你好",
"shopName":"byhieg",
"message":"查詢成功",
}
則咱們能夠簡單的構建這樣的一個Test.java文件,以下所示:
publicclassTest{
/**
status : 0
intro : byhieg
shopName : byhige
message :查詢成功
*/
privateintstatus;
privateString intro;
privateString shopName;
privateString message;
publicintgetStatus(){
returnstatus;
}
publicvoidsetStatus(intstatus){
this.status = status;
}
publicStringgetIntro(){
returnintro;
}
publicvoidsetIntro(String
intro){
this.intro = intro;
}
publicStringgetShopName(){
returnshopName;
}
publicvoidsetShopName(String
shopName){
this.shopName = shopName;
}
publicStringgetMessage(){
returnmessage;
}
publicvoidsetMessage(String
message){
this.message = message;
}
}
在得到到response以後,用以下代碼把Json文件解析成result對象。而後調用result對象的get方法就能夠獲得json文件中的intro的值和shopname的值,以及status和message.這裏就很少介紹了
Test result =newGson().fromJson(response.body().string,Test.class);
本文簡單介紹了okhttp的使用,更多內容關注微信公衆號mjw-java或訪問www.moliying.com