前段时间看了RxJava,发现跟他一起用的Retrofit,今天就把认识的他们俩个来总结梳理一下
一、什么是RxJava?(异步)
一个实现异步操作的库
具体的看下这个链接,写的超级详细,超级好
二、什么是Retrofit?
网络请求的封装。
Retrofit 是 Square 公司出品的默认基于 OkHttp 封装的一套 RESTful 网络请求框架,不了解 RESTful 概念的不妨去搜索学习下,RESTful 可以说是目前流行的一套 api 设计的风格,并不是标准。Retrofit 的封装可以说是很强大,里面涉及到一堆的设计模式,你可以通过注解直接配置请求,你可以使用不同的 http 客户端,虽然默认是用 http ,可以使用不同 Json Converter 来序列化数据,同时提供对 RxJava 的支持,使用Retrofit + OkHttp + RxJava + Dagger2可以说是目前比较潮的一套框架,但是需要有比较高的门槛。
Retrofit与picasso一样都是在okhttp基础之上做的封装,项目中可以直接用了。Retrofit因为也是Square出的,所以大家可能对它更崇拜些。Retrofit跟Volley是一个套路,但解耦的更彻底:比方说通过注解来配置请求参数,通过工厂来生成CallAdapter,Converter,你可以使用不同的请求适配器(CallAdapter), 比方说RxJava,Java8, Guava。你可以使用不同的反序列化工具(Converter),比方说json, protobuff, xml, moshi等等。炒鸡解耦,里面涉及到超多设计模式,个人觉得是很经典的学习案例。虽然支持Java8, Guava你可能也不需要用到。xml,protobuff等数据格式你也可能不需要解析。but,万一遇到鬼了呢。至于性能上,个人觉得这完全取决于请求client,也就是okhttp的性能,跟这些封装工具没太大关系。
Retrofit 是一个 RESTful 的 HTTP 网络请求框架的封装。注意这里并没有说它是网络请求框架,主要原因在于网络请求的工作并不是 Retrofit 来完成的。Retrofit 2.0 开始内置 OkHttp,前者专注于接口的封装,后者专注于网络请求的高效,二者分工协作,宛如古人的『你耕地来我织布』,小日子别提多幸福了。
我们的应用程序通过 Retrofit 请求网络,实际上是使用 Retrofit 接口层封装请求参数、Header、Url 等信息,之后由 OkHttp 完成后续的请求操作,在服务端返回数据之后,OkHttp 将原始的结果交给 Retrofit,后者根据用户的需求对结果进行解析的过程。讲到这里,你就会发现所谓 Retrofit,其实就是 Retrofitting OkHttp 了。
三、引用例子1
1、添加依赖
compile'com.squareup.retrofit2:retrofit:2.1.0' //引入retrofit所用的依赖
compile'com.squareup.retrofit2:converter-gson:2.1.0' //处理gson格式的数据,我们需要一个转换器,需要导入这个依赖
compile'com.squareup.retrofit2:adapter-rxjava:2.1.0' //这两个是我们需要配合Rxjava使用所添加的依赖
compile'io.reactivex:rxandroid:1.0.1'
2、添加权限
毫不疑问,我们现在学习的是网络请求框架,自然需要添加网络请求的权限
<uses-permission android:name="android.permission.INTENET"
3、重要的来啦
我们这是一个很简单的demo,获取登录信息,接口为:https://api.github.com/users/{user}
定义一个接口包service
第一个接口
public interfaceLoginService {
@GET("/users/{user}")
Call<LoginModel>login(@Path("user") String user);
}
GET的意思是发送一个GET请求,请求的地址是:baseUrl+"/users/{user}"。{user}类似于占位符的作用,具体类型由 repo(@Path("user") String user) 指定,这里表示 {user} 将是一段字符串。
Call<LoginModel>是一个请求对象,<LoginModel>表示返回结果,是一个LoginModel类型的实例。
public class LoginModel{
privateString login;
publicStringgetLogin() {
returnlogin;
}publicvoidsetLogin(String login) {
this.login = login;
}}
接下来构造一个retrofit对象
Retrofit retrofit =newRetrofit.Builder()
.baseUrl("https://api.github.com")
.addConverterFactory(GsonConverterFactory.create())
.build();
注意这里添加的 baseUrl 和 GsonConverter,前者表示要访问的网站,后者是添加了一个JSON转换器。
创建API接口对象
LoginService service = retrofit.create(LoginService.class);
Call modelCall = service.login("lslolly");
注意这里的 .login("lslolly") 取代了前面的 {user}。到这里,我们要访问的地址就成了:
https://api.github.com/users/lslolly
最后就可以发请求了
modelCall.enqueue(newCallback() {
@Override
public voidonResponse(Call call,Response response) {
Toast.makeText(MainActivity.this,"请求正确的结果是:"+response.body().getLogin(),Toast.LENGTH_LONG).show();
tv_result.setText("请求结果为:"+response.body().getLogin());
}
@Override
public voidonFailure(Call call,Throwable t) {
Toast.makeText(MainActivity.this,"请求错误的结果是:"+t.getMessage(),Toast.LENGTH_LONG).show();
}
下面说下POST请求参数设置
POST 的请求与 GET 请求不同,POST 请求的参数是放在请求体内的。所以当我们要为 POST 请求配置一个参数时,需要用到 @Body 注解:
Call<LoginModel>post(@Body User user);//这里的 User 类型是需要我们去自定义的:
public class User{
publicString username;
publicString password;
publicUser(String username,String password){
this.username = username;this.password = password;
}
//最后在获取请求对象时:
User user =newUser("lslolly","123456");
Call<LoginModel> model = service.post(user);
//完整代码实例如下
Retrofit retrofit =newRetrofit.Builder()
.baseUrl("https://api.github.com")
.addConverterFactory(GsonConverterFactory.create())
.build();
LoginService service = retrofit.create(LoginService.class);
Call<LoginModel>model =service.post(newUser("lolly","111111"));
model.enqueue(newCallback() {
@Override
public voidonResponse(Call call,Response response) {
Toast.makeText(MainActivity.this,"请求正确的结果是:"+response.body().getLogin(),Toast.LENGTH_LONG).show();
tv_result1.setText("请求结果为:"+response.body().getLogin());
}
@Override
public void onFailure(Call call,Throwable t) {
Toast.makeText(MainActivity.this,"请求错误的结果是:"+t.getMessage(),Toast.LENGTH_LONG).show();
}
});
四、例二
使用的是百度的API Store提供的API,地址在此:手机号码归属地__API服务_API服务_API Store.
1.设置model
访问该API返回的数据格式如下:
{ "errNum":0,
"retMsg":"success",
"retData": {
"phone":"15210011578",
"prefix":"1521001",
"supplier":"移动",
"province":"北京",
"city":"北京",
"suit":"152卡"}
}
根据返回结果我们创建数据对象PhoneResult,如下:
publicclassPhoneResult{/**
* errNum : 0
* retMsg : success
* retData : {"phone":"15210011578","prefix":"1521001","supplier":"移动","province":"北京","city":"北京","suit":"152卡"}
*/privateinterrNum;privateString retMsg;/**
* phone : 15210011578
* prefix : 1521001
* supplier : 移动
* province : 北京
* city : 北京
* suit : 152卡
*/
private RetDataEntity retData;
public void setErrNum(interrNum) {this.errNum = errNum; }
public void setRetMsg(String retMsg) {this.retMsg = retMsg; }publicvoidsetRetData(RetDataEntity retData) {this.retData = retData; }publicintgetErrNum() {returnerrNum; }publicStringgetRetMsg() {returnretMsg; }publicRetDataEntitygetRetData() {returnretData; }publicstaticclassRetDataEntity{privateString phone;privateString prefix;privateString supplier;privateString province;privateString city;privateString suit;publicvoidsetPhone(String phone) {this.phone = phone; }publicvoidsetPrefix(String prefix) {this.prefix = prefix; }publicvoidsetSupplier(String supplier) {this.supplier = supplier; }publicvoidsetProvince(String province) {this.province = province; }publicvoidsetCity(String city) {this.city = city; }publicvoidsetSuit(String suit) {this.suit = suit; }publicStringgetPhone() {returnphone; }publicStringgetPrefix() {returnprefix; }publicStringgetSupplier() {returnsupplier; }publicStringgetProvince() {returnprovince; }publicStringgetCity() {returncity; }publicStringgetSuit() {returnsuit; } }}
2.构造接口
public interface PhoneService{
@GET("/apistore/mobilenumber/mobilenumber")
Call<PhoneModel>getResult(@Header("apikey") String apikey, @Query("phone") String phone);}
3.使用
privatestaticfinalString BASE_URL ="http://apis.baidu.com";privatestaticfinalString API_KEY ="8e13586b86e4b7f3758ba3bd6c9c9135";privatevoidquery(){//1.创建Retrofit对象Retrofit retrofit =newRetrofit.Builder() .addConverterFactory(GsonConverterFactory.create())//解析方法.baseUrl(BASE_URL)//主机地址.build();//2.创建访问API的请求PhoneService service = retrofit.create(PhoneService.class); Call call = service.getResult(API_KEY, phoneView.getText().toString());//3.发送请求call.enqueue(newCallback() { @OverridepublicvoidonResponse(Call call, Response response) {//4.处理结果if(response.isSuccess()){ PhoneResult result = response.body();if(result !=null){ PhoneResult.RetDataEntity entity = result.getRetData(); } } } @OverridepublicvoidonFailure(Call call, Throwable t) { } });}
四、query,head
1.query
//如12306的查询接口https://kyfw.12306.cn/otn/lcxxcx/query?//purpose_codes=ADULT&queryDate=2016-03-18&from_station=BJP&to_station=CDW,写法如下:@GET("/otn/lcxxcx/query")Callquery(@Query("purpose_codes")Stringcodes, @Query("queryDate")Stringdate, @Query("from_station")Stringfrom, @Query("to_station")Stringto)
2.head
//比如要更新某个账户信息,其接口地址为/info,需要带的Header有设备信息device,//系统版本version,还要带请求参数要更新账户的id,代码如下:@POST("/info")Call updateInfo(@Header("device")Stringdevice, @Header("version")intversion, @Field("id")Stringid);
五、Retrofit中使用RxJava
参考Retrofit使用教程(三):Retrofit与RxJava初相逢
//使用RxJava我们则返回一个可被观测的PhoneResult:Observable,如下:
@GET("/apistore/mobilenumber/mobilenumber")ObservablegetPhoneResult(@Header("apikey") String apikey, @Query("phone") String phone);//为了能返回此对象,我们需要在创建Retrofit对象时添加一个RxJava对象的Adapter来自动完成:Retrofit retrofit =newRetrofit.Builder() .baseUrl(BASE_URL) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .build();//获取手机的归属地phoneService.getPhoneResult(PhoneApi.API_KEY, number) .subscribeOn(Schedulers.newThread())//子线程访问网络.observeOn(AndroidSchedulers.mainThread())//回调到主线程.subscribe(newObserver() { @OverridepublicvoidonCompleted() {} @OverridepublicvoidonError(Throwable e) {} @OverridepublicvoidonNext(PhoneResult result) {if(result !=null&& result.getErrNum() ==0) { PhoneResult.RetDataEntity entity = result.getRetData(); resultView.append("地址:"+ entity.getCity()); } } });}