Retrofit2.0通俗易懂的学习姿势,Retrofit2.0 + OkHttp3 + Gson + RxJava
2016-11-15 22:52
597 查看
Retrofit2.0通俗易懂的学习姿势,Retrofit2.0 + OkHttp3 + Gson + RxJava
Retrofit,因为其简单与出色的性能,也是受到很多人的青睐,但是他和以往的通信框架还是有点区别,不过放心,因为他本身还是挺简单的,所有我相信你看完这篇文章,对基本的请求是没什么问题的,其实现在网上这样的文章也有很多了,好了,那我们直接开车吧!
一.相关资料
Github:https://github.com/square/retrofit官网文档:http://square.github.io/retrofit/
二.square
square这家公司开源了很多非常优秀的项目,所有拿出来表示一家对他们这帮有开源精神的工程师表达
一下敬意,比如有这些项目:
OkHttp:https://github.com/square/okhttp
Picasso:https://github.com/square/picasso
三.准备工作
我们要使用Retrofit2.0,肯定要先集成进去,把项目这么一新建——RetrofitSample,然后我们看他的Github上,支持三种使用方式,这就没必要多说,各位看官想怎么添加就怎么添加
Jar: 点我下载
Maven:
<dependency> <groupId>com.squareup.retrofit2</groupId> <artifactId>retrofit</artifactId> <version>2.1.0</version> </dependency>
Gradle:
compile 'com.squareup.retrofit2:retrofit:2.1.0'
这里我们就直接用Gradle配置了,毕竟这样最简单,当然,我们配合OkHttp3更加的好用,所以添加源
compile 'com.squareup.okhttp3:okhttp:3.3.1'
这里可别忘了添加网络权限哦!
<uses-permission android:name="android.permission.INTERNET"/>
四.定义接口
我们要想学会使用,最佳的选择肯定是阅读官方的文档,第一句就是
“Retrofit turns your HTTP API into a Java interface”
需要我们定义一个接口,好的,那我们就依葫芦画瓢,写一个接口, 这里一定要记住哦,这个接口写起来是有一定的规范的,我们先看接口
http://gank.io/api/data/Android/10/1
这是Gank的接口,那我们应该怎么去写我们本地的接口呢,这是我们的Json
我们来定义一下我们的接口类,我们取名为GnakApi
import okhttp3.ResponseBody; import retrofit2.Call; import retrofit2.http.GET; public interface GnakApi { @GET("api/data/Android/10/1") Call<ResponseBody> getAndroidInfo(); }
仔细分析这个接口的定义,其实,这个接口我们可用这样去拆分
前面的baseUrl我们等一下直接定义,后面的,我们才是定义接口,我现在不需要返回值,所以我直接传了一个ResponseBody,而上面,我用GET请求,直接请求了api/data/Android/10/1,这样就能和我们的baseUrl拼接了,而后面的参数如果我们要改变的话,那接口方法就要传参了,这个我们等下来讲,再看下我们文档上的接口定义
public interface GitHubService { @GET("users/{user}/repos") Call<List<Repo>> listRepos(@Path("user") String user); }
这个是文档上提供的例子,我们可用发现,他同样的是GET请求,只不过他的返回值是一个List,类型是repo,repo就是他的实体类,传了一个path是一个参数,user的参数,这样也同样的可以和他的baseUrl拼接了他的baseUrl是什么呢,我们等下再说
五.简单请求
接口定义好了之后,我就开始请求了,这里我在布局里面写一个button做点击事件,再写一个textview做返回结果的呈现
<Button android:id="@+id/btn_requet" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/button_bg" android:text="请求" android:textAllCaps="false" android:textColor="@android:color/white"/> <TextView android:id="@+id/tv_result" android:layout_width="match_parent" android:layout_height="wrap_content"/>
好,那我们要怎么做呢?继续看文档
The Retrofit class generates an implementation of the GitHubService interface.
这里说直接把Retrofit的接口改造成一个类,那需要怎么做呢?首先,我们要创建一个Retrofit
Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://gank.io/") .build();
这里大家就看到我们的baseUrl了,就是我们Gank接口的前缀,我们现在有了retrofit,通过他的create方法就可以创建我们的接口对象了
GnakApi api = retrofit.create(GnakApi.class);
这里虽然是返回一个GnakApi,但是通过源码我们知道,这里的create实际上是通过代理的方式拿到的,可以看下
public <T> T create(final Class<T> service) { Utils.validateServiceInterface(service); if (validateEagerly) { eagerlyValidateMethods(service); } return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() { private final Platform platform = Platform.get(); @Override public Object invoke(Object proxy, Method method, Object... args) throws Throwable { // If the method is a method from Object then defer to normal invocation. if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } if (platform.isDefaultMethod(method)) { return platform.invokeDefaultMethod(method, service, proxy, args); } ServiceMethod serviceMethod = loadServiceMethod(method); OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.callAdapter.adapt(okHttpCall); } }); }
当然,这里不做深入的了解,我们现在就直接去调用我们的接口方法,他返回的就是一个Call
Call<ResponseBody> call = api.getAndroidInfo();
到这里,你会很奇怪,我去,怎么和okHttp这么像啊,如果单纯从简单请求来看,确实有一丢丢像,但是别急,Retrofit可没这么简单,我们又了call之后就直接请求了,一般我们都是异步请求
call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { try { String result = response.body().string(); Log.i(TAG, result); tv_result.setText(result); } catch (IOException e) { e.printStackTrace(); } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { } });
那我们直接点,运行一下
恩,可以看到,已经成功的请求到了结果了,这就是Retrofit的无参简单请求了,但是这里我们其实还可以做点文章,Retrofit + OkHttp + Gson更配哦,那我们添加Gson的Jar之后我们写一个实体类,也就是我们这个接口的javaBean,这里我使用的解析插件是Gsonformat
GankBean
import java.util.List; public class GankBean { private boolean error; private List<ResultsBean> results; public boolean isError() { return error; } public void setError(boolean error) { this.error = error; } public List<ResultsBean> getResults() { return results; } public void setResults(List<ResultsBean> results) { this.results = results; } public static class ResultsBean { /** * _id : 5827f41b421aa911d3bb7ecb * createdAt : 2016-11-13T13:03:23.38Z * desc : 独立全端开发的开源小作:简诗 2.0 * images : ["http://img.gank.io/b6be7a85-4035-437f-9521-65593fdbc48e"] * publishedAt : 2016-11-14T11:36:49.680Z * source : web * type : Android * url : https://www.v2ex.com/t/320154 * used : true * who : wingjay */ private String _id; private String createdAt; private String desc; private String publishedAt; private String source; private String type; private String url; private boolean used; private String who; private List<String> images; public String get_id() { return _id; } public void set_id(String _id) { this._id = _id; } public String getCreatedAt() { return createdAt; } public void setCreatedAt(String createdAt) { this.createdAt = createdAt; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } public String getPublishedAt() { return publishedAt; } public void setPublishedAt(String publishedAt) { this.publishedAt = publishedAt; } public String getSource() { return source; } public void setSource(String source) { this.source = source; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public boolean isUsed() { return used; } public void setUsed(boolean used) { this.used = used; } public String getWho() { return who; } public void setWho(String who) { this.who = who; } public List<String> getImages() { return images; } public void setImages(List<String> images) { this.images = images; } } }
用Gson是一键生成的,所以还是很方便
六.正常请求
我们做一个和官网一样的例子,实体类GankBean已经有了,那我们重新修改一下接口,让他返回这个实体类
import retrofit2.Call; import retrofit2.http.GET; public interface GnakApi { @GET("api/data/Android/10/1") Call<GankBean> getAndroidInfo(); }
去用的时候前面没有什么变化,只是返回的是实体类罢了
Call<GankBean> call = api.getAndroidInfo();
那我们异步的话,就很简单了
//异步 call.enqueue(new Callback<GankBean>() { @Override public void onResponse(Call<GankBean> call, Response<GankBean> response) { GankBean.ResultsBean bean = response.body().getResults().get(0); tv_result.setText( "_id:" + bean.get_id() + "\n" + "createdAt:" + bean.getCreatedAt() + "\n" + "desc:" + bean.getDesc() + "\n" + "images:" + bean.getImages() + "\n" + "publishedAt:" + bean.getPublishedAt() + "\n" + "source" + bean.getSource() + "\n" + "type:" + bean.getType() + "\n" + "url: " + bean.getUrl() + "\n" + "who:" + bean.getWho()); } @Override public void onFailure(Call<GankBean> call, Throwable t) { } });
这里就可以直接get出我们想要的值了吗?答案是否定的,我们运行之后可以看到这样一行错误
IllegalArgumentException: Unable to create converter for class com.liuguilin.retrofitsample.GankBean
下面该有一条更加重要的信息
Could not locate ResponseBody converter for class com.liuguilin.retrofitsample.GankBean.
这里很直观的说明,不能创建一个转换器,我擦,那怎么办?通过看文档,我们知道,我们需要去配置一个Gson,并不是我们的google.gson,我们添加源
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
单独说这个错误是因为我的学生很多都碰到过,所以这里提一下,然后我们配置一行
Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://gank.io/") .addConverterFactory(GsonConverterFactory.create()) .build();
现在运行就没问题了
恩,到这里,我们的基本请求就是这个样子,是不是很简单,我们只要前期配置好,并且根据api定义好接口,其他的都变得很方便了,配合Gson,那请求完了就可以直接拿值了,加上比较火的Dagger2注解,代表会变得十分的感人的,简洁,高效。
其实讲到这里,大家对他就已经有了一定的了解了,我们现在继续跟着文档走,来说下他的一些特性
七.Get的动态参数
大家都知道,我们的url大多数是拼接的,就像我们查询天气的接口,肯定是动态传一个城市的名字,对吧,这里我们换一个接口,就用天气的接口
官网:https://www.juhe.cn/docs/api/id/73
通过官网我们可用得知我们的接口是这样的
http://op.juhe.cn/onebox/weather/query?cityname=深圳&key=您申请的KEY
这里我们做一个简单的案例,默认cityname是深圳,我们就去拼接我们的key,那我们接口要怎么定义呢,我们写一个WeatherApi:
import retrofit2.Call; import retrofit2.http.GET; import retrofit2.http.Query; public interface WeatherApi { @GET("onebox/weather/query?cityname=深圳") Call<WeatherDataBean> getWeather(@Query("key") String key); }
这里我们可以看到,我们Get还是把我们的连接后半段传进去,但是这里最后拼接的时一个key,所以在传参的前面加上Query,如果你想两个参数,还有一个城市的话,你就多加一个参数咯,我们现在初始化一下
Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://op.juhe.cn/") .addConverterFactory(GsonConverterFactory.create()) .build(); api = retrofit.create(WeatherApi.class);
好的,拿到我们的接口对象就去用吧
Call<WeatherDataBean> call = api.getWeather("4ea58de8a7573377cec0046f5e2469d5"); //异步 call.enqueue(new Callback<WeatherDataBean>() { @Override public void onResponse(Call<WeatherDataBean> call, Response<WeatherDataBean> response) { String info = response.body().getResult().getData().getRealtime().getWeather().getInfo(); tv_result.setText("深圳天气:" + info); } @Override public void onFailure(Call<WeatherDataBean> call, Throwable t) { } });
这里的WeatherDataBean实在是数据太多了,所以我就没有显示出来,有需要的我会在本文的最后提供Sample的,这里我们请求,数据太多,我就直接请求一个了,来看运行之后的结果:
八.Get参数请求
上面的Get方法是一般的接口会这样做,但是有些请求,是有问题的,比如我们最上面的这个接口
http://gank.io/api/data/Android/10/1
他并没有像cityname或者key这样的名字,而是直接传参,其实他的参数含义是
//后面三个参数 //Android可接受参数 | Android | iOS | 休息视频 | 福利 | 前端 | App //count 最大 50 //page 是页数
这样的类型接口,我们一般是怎么去定义接口的呢?我们改造一下GankApi,这里我就直接传page了
import retrofit2.Call; import retrofit2.http.GET; import retrofit2.http.Path; public interface GnakApi { @GET("api/data/Android/10/{page}") Call<GankBean> getAndroidInfo(@Path("page") int page); }
可以看到,这里我们用大括号做占位符,然后用path关键字,一定要对应哦,其他的都差不多,紧接着我们请求
Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://gank.io/") .addConverterFactory(GsonConverterFactory.create()) .build();
api = retrofit.create(GankApi.class);
这样拿到我们的接口对象后直接请求
api.getAndroidInfo(1).enqueue(new Callback<GankBean>() { @Override public void onResponse(Call<GankBean> call, Response<GankBean> response) { tv_result.setText(response.body().getResults().get(0).getDesc()); } @Override public void onFailure(Call<GankBean> call, Throwable t) { } });
可以运行看到,依旧是可以拿到我们想要的值的,说明我们这个也是可以的
九.Get参数拼接
这个又是什么呢,我们把天气的api改一下你就知道了
import java.util.Map; import retrofit2.Call; import retrofit2.http.GET; import retrofit2.http.QueryMap; public interface WeatherApi { @GET("onebox/weather/query?") Call<WeatherDataBean> getWeather(@QueryMap Map<String, String> params); }
仔细看我这里GET后面传的并没有像cityname之类的参数,但是我这里有一个QueryMap ,传的是键值对,这样我们怎么去用呢?可以这样:
Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://op.juhe.cn/") .addConverterFactory(GsonConverterFactory.create()) .build(); api = retrofit.create(WeatherApi.class);
这里倒是没什么改变的,我们主要看接口传递的对象:
Map<String, String> params = new HashMap<>(); params.put("cityname", "深圳"); params.put("key", "4ea58de8a7573377cec0046f5e2469d5"); api.getWeather(params).enqueue(new Callback<WeatherDataBean>() { @Override public void onResponse(Call<WeatherDataBean> call, Response<WeatherDataBean> response) { } @Override public void onFailure(Call<WeatherDataBean> call, Throwable t) { } });
这里我们可以看到传map,然后map去put参数,这样最后请求的url就是
http://op.juhe.cn/onebox/weather/query?cityname=深圳&key=您申请的KEY
十.Post
POST请求的话,因为没有接口,所以我简单说一下,我也相信,你看到这里,get了解了post也相应的知道点,不过别急,我们还是会很详细的讲
import retrofit2.Call; import retrofit2.http.Body; import retrofit2.http.POST; public interface PostApi { @POST("user/new") Call<Result> postUser(@Body User user); }
这里POST的地址和之前的get也是一样的,这里返回一个Result是我们自家定义的结果,Body是表示参数,我需要一个User,那我们的User就是
public class User { private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
而我们的Result:
public class Result { private int yes; private int no; public int getYes() { return yes; } public void setYes(int yes) { this.yes = yes; } public int getNo() { return no; } public void setNo(int no) { this.no = no; } }
这两个都是没什么东西的,然后我们就可以直接去看怎么调用了
User user = new User(); user.setId(1); user.setName("lgl"); api.postUser(user).enqueue(new Callback<Result>() { @Override public void onResponse(Call<Result> call, Response<Result> response) { if (response.body().getYes() == 0) { Toast.makeText(MainActivity.this, "成功", Toast.LENGTH_SHORT).show(); } } @Override public void onFailure(Call<Result> call, Throwable t) { } });
我再这里传了一个user进去,细节不为过就是id和name,如果请求成功,那就返回0,失败就是1,这里服务端定义,这样我们就POST完成了
十一.Post提交表单
根据官网上的例子,还有一个更新用户的方法,用的就是提交表单
@POST("user/edit") Call<Result> editUser(@Field("id") int id, @Field("name") String name);
OK,我们用到的关键字是Field,这样去定义,然后直接调用这个方法
api.editUser(1, "liuguilin").enqueue(new Callback<Result>() { @Override public void onResponse(Call<Result> call, Response<Result> response) { if (response.body().getYes() == 0) { Toast.makeText(MainActivity.this, "成功", Toast.LENGTH_SHORT).show(); } } @Override public void onFailure(Call<Result> call, Throwable t) { } });
这样就把表单提交了,是不是很方便呢
最后还有一个PUT,他是多种文件类型上传,比如文件,图片,这里大家参考下官方文档
当然还有修改我们的Headers,这个很简单,看例子
@Headers("Cache-Control: max-age=640000") @GET("widget/list") Call<List<Widget>> widgetList();
这是官网的例子,但是你只需要添加Headers参数就可以穿了,而且因为他的参数时一个数组,你可以穿多个
按道理讲到这里算是完成了,我这里稍微的带点例子,讲下RxJava,因为我自己也不是很熟,所以我就讲我了解的这一块就好了
十二 Retrofit2.0+ RxJava
RxJava使用起来会让我们的代码更加的简洁,高效,那他和Retrofit2.0又会碰到什么样的激情呢?欢迎大家收看今天的人与自然……额 …跑题了,我们先做一些准备,主要是什么呢,根据官网来看,需要添加
//适配器 compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0' //RxJava compile 'io.reactivex:rxjava:1.1.6' //RxAndroid compile 'io.reactivex:rxandroid:1.2.1'
地址
RxJava:https://github.com/ReactiveX/RxJava
RxAndroid:https://github.com/ReactiveX/RxAndroid
这里我举一个最常见的例子来说明。那就是登录,登录成功后获取到user_id,再去请求用户信息,这里应该是两个请求对吧,我们先去写好接口,这里我们先用常规的方法去获取:
@POST("user/login") Call<User> login(@Field("username") String user, @Field("password") String password); @GET("user/info") Call<User> getUser(@Query("id") String id);
这里的两个接口,一个是登录,传参用户名和密码,还有一个是用id去查找用户信息的,那我们继续
Retrofit retrofit = new Retrofit.Builder() .baseUrl("baseUrl") .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build(); api = retrofit.create(PostApi.class);
这里我们需要增加addCallAdapterFactory为我们后面的Rx做准备,然后我们调用两次
api.login("liuguilin", "748778890").enqueue(new Callback<User>() { @Override public void onResponse(Call<User> call, Response<User> response) { if (response.isSuccessful()) { String id = response.body().getUser_id(); api.getUser(id).enqueue(new Callback<User>() { @Override public void onResponse(Call<User> call, Response<User> response) { Toast.makeText(MainActivity.this, "id:" + response.body().getId() + "name:" + response.body().getName(), Toast.LENGTH_SHORT).show(); } @Override public void onFailure(Call<User> call, Throwable t) { } }); } } @Override public void onFailure(Call<User> call, Throwable t) { } });
这样写代码是不是有点臃肿,别急,我们看看RxJava的写法,我们这里需要重新定义两个接口了
@POST("user/login") rx.Observable<User> loginForRX(@Body User user); @GET("user/info") rx.Observable<User> getUserForRX(@Query("id") String id);
这里的都是伪代码,注意看使用方法
api.loginForRX(new User("liuguilin", "748778890")).flatMap(new Func1<User, Observable<User>>() { @Override public Observable<User> call(User user) { return api.getUser(user.getUser_id()); } }).subscribe(new Action1<User>() { @Override public void call(User user) { Toast.makeText(MainActivity.this, "name:" + user.getName(), Toast.LENGTH_SHORT).show(); } });
这就是比较简洁的写法了,RxJava作为链式的表达式,响应式的操作还是很不错的,我会在我后面的博客继续深入的剖析,这里就不做太深入的了解了,因为感觉自己还没有到家吧,所以只是提一提,好了,到这里算是Ok了,你的Retrofit2.0学会了吗?
群:555974449
Sample:http://download.csdn.net/detail/qq_26787115/9683939
相关文章推荐
- retrofit2.0通俗易懂的学习姿势,Retrofit2.0 + OkHttp3 + Gson + RxJava
- Retrofit2.0通俗易懂的学习姿势,Retrofit2.0 + OkHttp3 + Gson + RxJava
- Retrofit2.0通俗易懂的学习姿势,Retrofit2.0 + OkHttp3 + Gson + RxJava
- Retrofit2.0通俗易懂的学习姿势,Retrofit2.0 + OkHttp3 + Gson + RxJava
- Android Retrofit 2.0(二)使用教程OkHttp3 + Gson + RxJava
- retrofit2.0+okhttp3+rxjava的封装(简单好用)
- Rxjava+ReTrofit+okHttp深入浅出-终极封装特殊篇(替换Gson返回)
- 从零开始搭建一个主流项目框架(三)—RxJava2.0+Retrofit2.0+OkHttp
- RxJava+Retrofit+OkHttp深入浅出-终极封装六特殊篇(变种String替换Gson自由扩展)
- RxJava+Retrofit+OkHttp深入浅出-终极封装六特殊篇(变种String替换Gson自由扩展)
- Retrofit 2.0使用详解,配合OkHttp、Gson,Android最强网络请求框架
- RxJava+Retrofit+OkHttp深入浅出-终极封装六特殊篇(变种String替换Gson自由扩展)
- Retrofit 2.0,RxJava(Android), OkHttp3.3
- retrofit okhttp RxJava bk Gson Lambda 综合示例【配置】
- Android框架学习之Retrofit(二)RxJava和Retrofit2.0的结合使用
- RxAndroid+RxJava+Gson+retrofit+okhttp初步搭建android网络请求框架
- 天气预报项目学习总结(- ButterKnife - Retrofit 2.0(okhttp) - Rxjava - Jackson - Ormlite - Mosby简单使用总结)
- 基于Rxjava+Retrofit+Okhttp+LeanCloud的完整项目(段子手),供大家学习与交流
- Retrofit 2.0使用详解,配合OkHttp、Gson,Android最强网络请求框架
- Retrofit2.0的学习以及Rxjava与Retrofit2的结合使用