原文鏈接:
http://www.reibang.com/p/a8b88c7fe831
http://blog.csdn.net/qq_24889075/article/details/52181133
概述
在學習 Retrofit2 的過程中受到了一些阻力,現(xiàn) Retrofit2 學會使用了,特此寫此文驗證所學知識。同時也希望幫助和我一樣在學習Retrofit2遇到困難的猿們先煎。
當我在剛開始學習 Retrofit2 的時候并不知道Retrofit2是什么東西,后來逐漸了解 “它可能是一個方便我們網(wǎng)絡(luò)請求的庫 诅妹,可以幫我們讓請求網(wǎng)絡(luò)變得更靈活郎汪、易于維護”森瘪。然后還可以和時下比較火熱的RxJava進行完美融合刹帕。
先看看如何使用吵血,如何進行一個簡單的Get/Post請求
Retrofit2 入門
首先在build.gradle中添加如下代碼,添加Retrofit2庫
compile 'com.squareup.retrofit2:retrofit:2.1.0'
有的教程里寫要手動添加okhttp的庫轩拨,其實是不需要的践瓷,因為retrofit2封裝了okhttp,不信自己編譯下看看:
添加完庫院喜,我們開始正文亡蓉。
我們在項目中進行網(wǎng)絡(luò)請求時,肯定不是一個地址吧喷舀,那么這些請求地址存放在哪呢砍濒?是在哪個類里請求就在哪個類里存放,還是統(tǒng)一放在一個專門存地址的類中呢硫麻?
我在學習Android期間就是哪里有請求就放哪里爸邢,后來有人告訴我要集中存放。于是后來就建立一個AppURL.java所有地址都存放這里拿愧。
然而Retrofit2這里也可以這么理解:專門有一個‘地方’來存儲鏈接地址(也可以創(chuàng)建多個‘地方’存儲)杠河。這個‘地方’不是類而是接口,在這個接口中可以設(shè)定請求地址的一些信息浇辜。就像這樣:
public interface AppURL {
@GET("index")
Call<ResponseBody> getIndex();
...
...
// 可以存儲多個連接地址
}
說明:
接口名“AppURL ”可以隨意定義券敌,根據(jù)自己喜好。
第一行:代表get請求,請求地址為“設(shè)定的BaseURL/index” (BaseURL設(shè)定在下面介紹如何設(shè)定)
第二行:getIndex是方法名;Call<ResponseBody>是默認返回類型柳洋,暫且不要管能干什么待诅。
下面我們看下如何使用這些地址進行網(wǎng)絡(luò)請求:
- 創(chuàng)建Retrofit對象,并設(shè)定BaseURL
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://www.這里是BaseURL.com/")
.build();
需要注意的是BaseURL必須以‘/’結(jié)尾
- 獲取“AppURL”對象(創(chuàng)建請求服務)
AppURL url= retrofit.create(AppURL.class);
- 用AppURL對象得到具體請求對象(獲取請求服務方法 )
Call<ResponseBody> call = url.getIndex();
后期也會在這一步中進行設(shè)置鏈接參數(shù)熊镣、請求頭等
- 開始(異步)請求
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
Log.e("tag", response.body().toString());//獲得數(shù)據(jù)
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.e("tag", t.getMessage());//請求失敗
}
});
好了卑雁,現(xiàn)在一個簡單的網(wǎng)絡(luò)請求就寫完了募书。不是很難吧(當時我可是覺得挺難 _)
單單會這些是遠遠不夠的,那么我們?nèi)绾蝸頋M足項目中各種各樣的需求呢测蹲?請繼續(xù)看
Retrofit2 進階
自動解析
其實在Retrofit2中莹捡,我們不用自己來解析數(shù)據(jù),Retrofit2可以幫我們自動解析弛房,怎么做呢道盏?請看:
- 添加
在Retrofit2中是用Gson解析的,所以我們要在build.gradle中添加文捶。
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
有寫教程說還有添加gosn庫荷逞,經(jīng)過測試是不需要的,converter-gson中已經(jīng)封裝了gson庫粹排。
需要注意的是converter-gson和retrofit版本號應為一致种远,在這里我都用2.1.0
- 創(chuàng)建Bean
創(chuàng)建一個JavaBean,用于解析服務器返回數(shù)據(jù)顽耳。就和我們平常自己解析創(chuàng)建的Bean一樣坠敷,推薦用As的插件JsonFormat,挺方便的射富。
我們創(chuàng)建一個Bean起名為MBean.java(隨便起的) - 為retrofit添加addConverterFactory
添加后的代碼如下:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://www.這里是BaseURL.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
- 修改泛型
//在AppURL 接口中修改:
@GET("index")
Call<MBean> getIndex();
Call<MBean> call = url.getIndex();
//調(diào)用服務請求時的修改
call.enqueue(new Callback<MBean>() {
@Override
public void onResponse(Call<MBean> call, Response<MBean> response) {
Log.e("tag", response.body().toString());//解析好的數(shù)據(jù)
}
@Override
public void onFailure(Call<MBean> call, Throwable t) {
Log.e("tag", t.getMessage());
}
});
這樣輸出的就直接是用Gson解析好的MBean數(shù)據(jù)了膝迎。
retrofit不僅僅只支持gson,還支持其他許多json解析庫胰耗。 如:
Jackson限次、Moshi、Protobuf柴灯、Wire卖漫、Simple XML、Scalars (primitives, boxed, and String) 具體請看官網(wǎng)
固定地址/路徑替換
說到固定地址了赠群,那么固定地址長什么樣呢羊始?
http://www.BaseURL.com/index
http://www.BaseURL.com/user
http://www.BaseURL.com/login
http://www.BaseURL.com/register/qq
http://www.BaseURL.com/register/wechat
那么應該如何請求呢?除了上面例子中的寫法還可以這樣寫:
@請求類型("{name}")
Call<返回類型> 方法名(@path("name") String name);
如:
@GET("{name}")
Call<MBean> get(@Path("name") String urlName);
//如果想訪問登錄的鏈接查描,在使用時就直接url.get("login");就可以突委。這樣請求的地址就是http://www.BaseURL.com/login 是不是很方便
//注意@Path和{}中的參數(shù)名要一致
@Path的應該作用暫且理解為 為上面的GET請求傳值吧
帶參地址
帶參地址長這樣子:
www.BaseURL.com/login?page=1
www.BaseURL.com/movieTop?start=1&count=5
www.BaseURL.com/login?username=testuser&password=123456
上個用的是@Path,這回用的是@Query其實和@Path一樣
直接看例子:
@GET("movieTop")
Call<MBean> get(@Query("start") int start, @Query("count") int count);
//假設(shè)想查詢電影排行榜的第1-5名冬三,則使用時候是這樣:
Call<MBean> call = url.get(1, 5);
//請求的地址是這樣:www.BaseURL.com/movieTop?start=1&count=5
Post帶Body請求
使用@Body來聲明即可匀油,如下:
@POST("/aaa")
Call<MBean> send( @Body UserInfo body);
//使用
Call<MBean> call=url.send();
這里的UserInfo就是要發(fā)送的實體,Retrofit2 會自動轉(zhuǎn)成Gson
學到這里长豁,一般的網(wǎng)絡(luò)請求都可以了進行钧唐,可以應付一陣子了。
還有一些要求較高的請求匠襟,請看下節(jié)钝侠。
Retrofit2 大成
如果看到這里该园,相信對Retrofit2的基本請求會用了,那么這節(jié)就說一說其他的網(wǎng)絡(luò)請求帅韧。
表單(FormUrlEncoded)
我們可以使用@FormUrlEncoded注解來發(fā)送表單數(shù)據(jù)里初。使用 @Field注解和參數(shù)來指定每個表單項的Key,value為參數(shù)的值忽舟。
@FormUrlEncoded
@POST("user/login")
Call<User> updateUser(@Field("username") String name, @Field("password") String pass);
單文件上傳(Multipart)
@Multipart
@POST("register")
Call<User> registerUser(
@Part MultipartBody.Part headPhoto,
@Part("username") RequestBody userName,
@Part("password") RequestBody passWord
);
//使用
MediaType textType = MediaType.parse("text/plain");
RequestBody name = RequestBody.create(textType, "二傻子");
RequestBody pass = RequestBody.create(textType, "123456");
RequestBody photoRequestBody = RequestBody.create(MediaType.parse("image/png"), 文件對象);
MultipartBody.Part photo = MultipartBody.Part.createFormData("上傳的key", "文件名.png", photoRequestBody);
Call<User> call = url.registerUser(photo,name, pass);
@Part 后面支持三種類型双妨,{@link RequestBody}、{@link okhttp3.MultipartBody.Part} 叮阅、任意類型刁品;
動手測試:username的RequestBody 換成String是否可以
多文件上傳
@Multipart
@POST("register")
Call<User> registerUser(@PartMap Map<String, RequestBody> params, @Part("password") RequestBody password);
//使用
RequestBody photo = RequestBody.create(MediaType.parse("image/png"), 文件對象2);
RequestBody photo = RequestBody.create(MediaType.parse("image/png"), 文件對象2);
Map<String,RequestBody> photos = new HashMap<>();
photos.put("對應的key1"; filename=\"文件名1.png", photo1);
photos.put("對應的key2"; filename=\"文件名2.png", photo2);
photos.put("username", RequestBody.create(null, "二傻子"));
Call<User> call = userBiz.registerUser(photos, RequestBody.create(null, "123456"));
也可以都塞Map里上傳,也可以只在Map中上傳文件浩姥,隨你嘍~
文章結(jié)尾有參考鏈接挑随。不一樣的上傳方式。
文件和參數(shù)混合上傳
比如修改用戶信息:頭像勒叠、用戶名
@Multipart
@POST("地址")
Call<User> head(@Part("key") RequestBody username,
@Part("key\"; filename=\"完整的用戶名") RequestBody img,
@Part("key") RequestBody sex,
@Part("key") RequestBody key
);
//使用
Call<User> call =url.head(
RequestBody.create(MediaType.parse("text/plain"), username),
RequestBody.create(MediaType.parse("image/*"), 圖片對象),
RequestBody.create(MediaType.parse("text/plain"), sex),
RequestBody.create(MediaType.parse("text/plain"), key)));
不知道還有沒有其他方法 以后有時間研究下
請求頭
- 固定請求頭
@GET("地址")
@Headers("Accept-Encoding: application/json")
Call<返回類型> 方法名();
// 請求結(jié)果:
// GET 地址 HTTP/1.1
// Accept-Encoding: application/json
- 動態(tài)請求頭
@GET("地址")
Call<返回類型> 方法名(@Header("Location") String location);
//使用
url.方法名("參數(shù)");
// 請求結(jié)果:
// GET 地址 HTTP/1.1
// Location: 參數(shù)
- 固定+動態(tài)
@GET("地址")
@Headers("Accept-Encoding: application/json")
Call<返回類型> 方法名(@Header("Location") String location);
//使用
url.方法名("參數(shù)");
// 請求結(jié)果:
// GET 地址 HTTP/1.1
// Accept-Encoding: application/json
// Location: 參數(shù)
其他
注意XXXMap的使用兜挨, 比如@PathMap,@FieldMap等眯分,具體怎么使用拌汇,可以自己研究,研究不出來的可以參考結(jié)尾處的文章弊决。
下載文件得說說噪舀,在Retrofit2中下載文件是默認存儲到緩存中,也就是說不能進行大的文件下載丢氢,如果要下載大文件要用 @streaming 傅联。但話說回來了先改,下載文件我們可以不用Retrofit2啊疚察,直接用okhttp不就得啦
我們是可以添加 okhttpclient 到retrofit中去,這樣可以來統(tǒng)一的log管理仇奶,給每個請求添加統(tǒng)一的header等貌嫡,那么我們沒有添加為什么沒有報錯呢? 因為在build()方法中會判斷是否為空该溯,如果我們沒有添加okhttpclient 則就是空了岛抄,那么retrofit會自動給我們添加了一個new OkHttpClient();
execute是同步執(zhí)行 需要在子線程中執(zhí)行、enqueue是異步執(zhí)行狈茉。
看下我這幾個圖夫椭,整理一下思路吧
以上表格中的除HTTP以外都對應了HTTP標準中的請求方法,而HTTP注解則可以代替以上方法中的任意一個注解,有3個屬性:method氯庆、path蹭秋、hasBody, 這里是用HTTP注解實現(xiàn)的例子
public interface BlogService {
/**
* method 表示請的方法扰付,不區(qū)分大小寫
* path表示路徑
* hasBody表示是否有請求體
*/
@HTTP(method = "get", path = "blog/{id}", hasBody = false)
Call<ResponseBody> getFirstBlog(@Path("id") int id);
}
注1:{占位符}和PATH盡量只用在URL的path部分,url中的參數(shù)使用Query和QueryMap 代替仁讨,保證接口定義的簡潔
注2:Query羽莺、Field和Part這三者都支持數(shù)組和實現(xiàn)了Iterable接口的類型,如List洞豁,Set等盐固,方便向后臺傳遞數(shù)組。
Call<ResponseBody> foo(@Query("ids[]") List<Integer> ids);
//結(jié)果:ids[]=0&ids[]=1&ids[]=2
Retrofit2 獨斷萬古
首先說下如何和當前火熱的RxJava進行配合使用丈挟。
- 引入RxJava支持 (版本號要一致)
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
- 寫接口
@GET(" ^_^ ")
Observable<MBean> get();
- 通過RxJavaCallAdapterFactory為Retrofit添加RxJava支持
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://www.BaseURL.com/")
.addConverterFactory(GsonConverterFactory.create())//自動通過Gson轉(zhuǎn)josn刁卜,上面有提到
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())//添加RxJava支持
.build();
- 使用
url.get()
.subscribeOn(Schedulers.io())
.subscribe(new Subscriber<MBean>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(MBean mBean) {
}
});
根據(jù)需要添加RxAndroid,這個版本號沒有要求曙咽。
剩下的內(nèi)容講的主要是進行自定義 Converter 和 自定義CallAdapter长酗。還有就是源碼的解析。
這里可以參考結(jié)尾處的鏈接桐绒,不獻丑了夺脾。
Retrofit2 + RxJava 第一次使用出現(xiàn)的問題
忘記添加
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
好的Retrofit2 + RxJava Demo參考:
https://github.com/rengwuxian/RxJavaSamples
參考地址
這些是我在學習過程中收集的一些資料,個人感覺還不錯茉继。
本文部分內(nèi)容來自于下面部分文章
鴻洋:http://blog.csdn.net/lmj623565791/article/details/51304204#t1
圖片來源(經(jīng)過作者授權(quán)拿的圖):http://www.reibang.com/p/308f3c54abdd
其他博客:
http://blog.csdn.net/ljd2038/article/details/51046512
http://blog.csdn.net/biezhihua/article/details/49232289
多文件上傳參考:
http://www.chenkaihua.com/2016/04/02/retrofit2-upload-multipart-files.html
http://www.reibang.com/p/acfefb0a204f
https://futurestud.io/blog/retrofit-getting-started-and-android-client
小說看多了咧叭,起的名有些怪。烁竭。菲茬。 見諒啊 _