網(wǎng)上關(guān)于Retrofit(這里指的是Retrofit2包里的Retrofit)的文章已經(jīng)普天蓋地了!為什么還要寫這一篇呢?“扔物線”給了我啟發(fā)则奥!人們還是喜歡原創(chuàng)的東西考润,而不是東拼西湊的東西!有價(jià)值的東西读处!當(dāng)然糊治,現(xiàn)在稍微值錢一點(diǎn)的東西都拿到淘寶賣了!指望“賞”來兩個(gè)小錢發(fā)不了財(cái)罚舱!當(dāng)然不是不想你們“賞”錢井辜,而是非常想!因?yàn)檫@是文章價(jià)值的體現(xiàn)管闷,和對(duì)筆者的充分肯定粥脚!
我的筆鋒非常犀利,那是寫評(píng)論文章包个!現(xiàn)在寫的是技術(shù)文章刷允,會(huì)充分體現(xiàn)我務(wù)實(shí)求是的人格魅力!沒有深?yuàn)W的東西碧囊,也不會(huì)故弄玄虛树灶,踏踏實(shí)實(shí)的人,寫踏踏實(shí)實(shí)的文章糯而。
屁話一大堆了天通!急性子的人早開流了!言歸正傳熄驼!
一像寒、編寫Json數(shù)據(jù)的Repo類
我用JAVA開發(fā)了一個(gè)全功能的服務(wù)器,除了java庫(kù)谜洽,沒有用任何第三方庫(kù)萝映!今天不打算用我自己的服務(wù)器數(shù)據(jù)!就用Retrofit 官網(wǎng)提供的示例數(shù)據(jù)阐虚!
編寫程序前我喜歡看一看json數(shù)據(jù)是個(gè)什么鬼序臂?瀏覽器打開輸入https://api.github.com/users/octocat/repos
,顯示了下列數(shù)據(jù)格式实束,使用Retrofit返回的數(shù)據(jù)也應(yīng)該是一樣的奥秆,所以就寫成:
Retrofit 返回的json數(shù)據(jù)格式為:
[{"id":18221276,"name":"git-consortium","full_name": "octocat/git-consortium","owner": {"login": "octocat","id": 583231,"avatar_url": "https://avatars3.githubusercontent.com/u/583231?v=4",...},...},{...}...]
是一個(gè)對(duì)象數(shù)組,建立對(duì)應(yīng)的POJO類咸灿,字段實(shí)在太多了构订!我們利用一小部分字段建一個(gè)Repo類,它里面還包含一個(gè)Owner類避矢。有人會(huì)說字段是否應(yīng)該完全對(duì)應(yīng)悼瘾,缺少了行不行囊榜?我試驗(yàn)過了,完全可行亥宿!我也發(fā)表過很多文章卸勺,還得過獎(jiǎng),每一篇文章都是自己的實(shí)踐過程的總結(jié)烫扼!
public class Repo {
public int id;
public String name;
public String full_name;
public Owner owner;
}
public class Owner {
public String login;
public int id;
public String avatar_url;
}
二曙求、Retrofit沒有轉(zhuǎn)換器沒有調(diào)用適配器,還要使用RxJava
看了標(biāo)題挺吸引人的映企!是不是吹牛拔蛴?沒有真本事就會(huì)吹堰氓!
我就拿Retrofit的示例演示一下挤渐,直接貼代碼,你們拷貝粘貼到你們的開發(fā)工具中豆赏,看看是不是吹牛挣菲?
package com.ueuo.retrofit2;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.List;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Retrofit;
import retrofit2.http.GET;
import retrofit2.http.Path;
public class Test3 {
public interface GitHubService {
@GET("users/{user}/repos")
Call<ResponseBody> listRepos(@Path("user") String user);
}
public static void main(String[] args) throws IOException {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
Call<ResponseBody> repos = service.listRepos("octocat");
ResponseBody response = repos.execute().body();
Gson gson =new Gson();
Type type = new TypeToken<List<Repo>>() {}.getType();
List<Repo> zla = gson.fromJson(response.charStream(), type);
Observable<List<Repo>> observable = Observable.just(zla);
observable.flatMap(new Function<List<Repo>, ObservableSource<Repo>>(){
@Override
public ObservableSource<Repo> apply(List<Repo> paramT) throws Exception {
return Observable.fromIterable(paramT);
}
}).subscribe(new Consumer<Repo>(){
@Override
public void accept(Repo repo) throws Exception {
System.out.println(repo.name);
System.out.println(repo.full_name);
System.out.println(repo.owner.avatar_url);
}
});
}
}
我在Eclipse里運(yùn)行正常富稻,結(jié)果是:
git-consortium
octocat/git-consortium
https://avatars3.githubusercontent.com/u/583231?v=4
......
從上面示例可以看出掷邦,Retrofit純粹是脫褲子放屁多次一舉!繞了一大圈還是這個(gè)結(jié)果椭赋!不信的話我們就來看看抚岗!
三、Retrofit添加Converter和CallAdapter
Retrofit請(qǐng)求數(shù)據(jù)哪怔,以及與RxJava配合使用宣蔚,需要用到Converter和CallAdapter!這是非常關(guān)鍵的地方认境,被很多作者忽略胚委,或者不想把真象告訴你們!
要記住Converter是轉(zhuǎn)換json數(shù)據(jù)到j(luò)ava類叉信,例如Repo類亩冬,或者某個(gè)類型,例如List<Repo>硼身。
而CallAdapter是把Converter已經(jīng)轉(zhuǎn)換到的類或者類型硅急,變成RxJava的Observable對(duì)象!
我們一起來看示例:
package com.ueuo.retrofit2;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.CallAdapter;
import retrofit2.Converter;
import retrofit2.Retrofit;
import retrofit2.http.GET;
import retrofit2.http.Path;
/**
* https://api.github.com/users/octocat/repos
*
* @author xbn
*
* 自定義Converter和 CallAdapter
*/
public class Test2 {
public interface GitHubService {
@GET("users/{user}/repos")
Observable<List<Repo>> listRepos(@Path("user") String user);
}
public static class CustomConverter implements Converter<ResponseBody, List<Repo>> {
public static final CustomConverter INSTANCE = new CustomConverter();
public static CustomConverter create() {
return INSTANCE;
}
@Override
public List<Repo> convert(ResponseBody value) throws IOException {
// ResponseBody --> List<Repo>
Gson gson = new Gson();
Type type = new TypeToken<List<Repo>>() {}.getType();
return gson.fromJson(value.charStream(), type);
}
}
public static class CustomConverterFactory extends Converter.Factory {
public static final CustomConverterFactory INSTANCE = new CustomConverterFactory();
public static CustomConverterFactory create() {
return INSTANCE;
}
// 我們只關(guān)實(shí)現(xiàn)從 ResponseBody 到 List<Repo> 的轉(zhuǎn)換佳遂,所以其它方法可不覆蓋
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
Type rawtype = getRawType(type);
if(rawtype == List.class && type instanceof ParameterizedType) {
return CustomConverter.create();
}
//其它類型我們不處理营袜,返回null就行
return null;
}
}
public static class CustomCallAdapter implements CallAdapter<List<Repo>, Observable<List<Repo>>> {
private final Type responseType;
//接口方法的返回類型的泛型類型 responseType
CustomCallAdapter(Type responseType) {
this.responseType = responseType;
}
@Override
public Type responseType() {
return responseType;
}
//Call<List<Repo>> -- Retrofit2的
public Observable<List<Repo>> adapt(Call<List<Repo>> call) {
Observable<List<Repo>> observable;
try {
observable = Observable.just(call.execute().body());
return observable;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
public static class CustomCallAdapterFactory extends CallAdapter.Factory {
public static final CustomCallAdapterFactory INSTANCE = new CustomCallAdapterFactory();
public static CustomCallAdapterFactory create() {
return INSTANCE;
}
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
//接口方法的返回類型
Class<?> rawType = getRawType(returnType);
//返回值必須是Observable并且?guī)в蟹盒? if (rawType == Observable.class && returnType instanceof ParameterizedType) {
//接口方法的返回類型的泛型類型
Type callReturnType = getParameterUpperBound(0, (ParameterizedType) returnType);
return (CallAdapter<?, ?>) new CustomCallAdapter(callReturnType);
}
return null;
}
}
public static void main(String[] args) throws IOException {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(CustomConverterFactory.create())
.addCallAdapterFactory(CustomCallAdapterFactory.create())
.build();
GitHubService service = retrofit.create(GitHubService.class);
Observable<List<Repo>> repos = service.listRepos("octocat");
repos.flatMap(new Function<List<Repo>, ObservableSource<Repo>>(){
@Override
public ObservableSource<Repo> apply(List<Repo> paramT) throws Exception {
return Observable.fromIterable(paramT);
}
}).subscribe(new Consumer<Repo>() {
@Override
public void accept(Repo paramT) throws Exception {
System.out.println(paramT.full_name);
}
});
}
}
拷貝到IDE運(yùn)行應(yīng)該輸出:
octocat/git-consortium
octocat/hello-worId
octocat/Hello-World
......
關(guān)鍵的地方是:
@Override
public List<Repo> convert(ResponseBody value) throws IOException {
// ResponseBody --> List<Repo>
Gson gson = new Gson();
Type type = new TypeToken<List<Repo>>() {}.getType();
return gson.fromJson(value.charStream(), type);
}
在Converter中Retrofit的請(qǐng)求數(shù)據(jù)還是原始數(shù)據(jù)!上面轉(zhuǎn)換成為L(zhǎng)ist<Repo>類型的對(duì)象丑罪。
然后數(shù)據(jù)交到CallAdapter:
public Observable<List<Repo>> adapt(Call<List<Repo>> call) {
Observable<List<Repo>> observable;
try {
observable = Observable.just(call.execute().body());
return observable;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
可以看到adapt()方法中的參數(shù)類型是Call<List<Repo>> 荚板!這個(gè)類型是Retrofit的或者說是Retrofit2的(我們使用的是Retrofit2凤壁,類名還是Retrofit。)有人追究過源碼跪另,說是執(zhí)行實(shí)際網(wǎng)絡(luò)請(qǐng)求的是OkHttp3的Call客扎。我也看了源碼,沒有追得很深罚斗,感覺差不多有那么回事徙鱼,所以就信了別人的。在這個(gè)Call上查到的是一個(gè)Retrofit2包里的接口针姿。
四袱吆、這些是從哪里學(xué)來的?
我非常保守距淫!追求程序的精簡(jiǎn)绞绒,抵觸第三方庫(kù)!現(xiàn)在看來落后了榕暇!利用第三方庫(kù)可以快速輕松的開發(fā)軟件蓬衡,已經(jīng)是一股潮流了!我需要進(jìn)步彤枢!我的Retrofit2的第一任老師是ikidou的“你真的會(huì)用Retrofit2嗎?Retrofit2完全教程http://www.reibang.com/p/308f3c54abdd
狰晚,他還提供了測(cè)試服務(wù)器RESTServer,非常感謝缴啡!同時(shí)也要感謝我的不懈努力壁晒!它的示例代碼,引入Android Studio3.0不行业栅,引入Eclipse也不行秒咐,本來打算放棄了,心想還有難倒程序員的碘裕?携取!就試著把源文件拷來拷去,搞定了帮孔!