Retrofit系列二

  • 1.为什么会选择Retrofit【Okhttp/retrofit/android-async-http/volley】

    • 1)个人比较推荐Square开源组合,用Retrofit(目前已经是2.0+)+OkHttp基本上已经可以处理任何业务场景了,Square开源库质量还是值得信赖的。
    • 2)Retrofit的特点我个人认为是简化了网络请求流程,同时自己内部对OkHtttp客户端做了封装,同时2.x把之前1.x版本的部分不恰当职责都转移给OkHttp了(例如Log,目前用OkHttp的Interceptor来实现),这样的好处是职责清晰,Retrofit做自己该做的事儿。
    • 3)而且Retrofit提供不同的Json Converter实现(也可以自定义),同时提供RxJava支持(返回Observable对象),配合Jackson(或者Gson)和RxJava,再加上Dagger2,你的效率至少可以提高一倍。
    • 4)okhttp是android平台最好的网络库
    • 5)volley是一个简单的异步http库,仅此而已。缺点是不支持同步,这点会限制开发模式;不能post大数据,所以不适合用来上传文件。
    • 6)android-async-http。与volley一样是异步网络库,但volley是封装的httpUrlConnection,它是封装的httpClient,而android平台不推荐用HttpClient了,所以这个库已经不适合android平台了
    • 7)okhttp是高性能的http库,支持同步、异步,而且实现了spdy、http2、websocket协议,api很简洁易用,和volley一样实现了http协议的缓存。picasso就是利用okhttp的缓存机制实现其文件缓存,实现的很优雅,很正确,反例就是UIL(universall image loader),自己做的文件缓存,而且不遵守http缓存机制。
    • 8)retrofit与picasso一样都是在okhttp基础之上做的封装,项目中可以直接用了。
    • 9)picasso、uil都不支持inbitmap,项目中有用到picasso的富图片应用需要注意这点。
    • 10)AndroidAsync这个网络库使用了nio的方式实现的。okhttp没有提供nio selector的方式,不过nio更适合大量连接的情况,对于移动平台有点杀鸡用牛刀的味道。
    • 11)每个开源或多或少会有各种坑,你要做的就是踩坑,填坑,再踩坑,再填坑
    • 12)如果是标准的RESTful API,那么用Retrofit会非常爽!网络交互部分代码量可以减少90%。同时支持Gson,契合度很高。另外,Retrofit和okhttp是亲兄弟,建议一起用,okhttp是底层库,能够支持一些非标准的HTTP方法,比如PATCH方法。
    • 13)Volley自己的定位是轻量级网络交互,适合大量的,小数据传输,如果你的项目比较大,那么目测还得把volley再次封装才会好用一些。
    • 14)okhttp 和 async http是一个基础的通信库,都很强大,但需要自己封装使用才更方便。另外okhttp已经被谷歌官方用在android源码中了。
    • 15)retrofit和 volley是属于比较高级点的封装库了 其中 retrofit是默认使用okhttp volley也支持okhttp作为其底层通信的部件。retrofit的特点是使用清晰简单的接口,非常方便,而 volley在使用的时候也还简单,不过要使用高级一点的功能需要自己自定义很多东西
    • 16)推荐retrofit+okhttp,:demo:无论用哪个网络库,都要封装一层,别问我怎么知道的。
    • 17)如果项目比较新,并且你想学习使用rxjava,那么推荐retrofit+okhttp配合使用,代码量少了很多很多,写起来很爽,但是有一点需要注意,retrofit没有网络缓存。
    • 18)首先Retrofit与okhttp是同一家公司开发出来的,不同之处在与Retrofit是用注解实现了,注解的优点这里就不多说了,而且Retrofit支持直接将Json字符串解析为JavaBean,而且不局限与一种解析库(Gson,Jackson等,只需要简单的配置就可以方便的替换),最为强大的一点在于Retrofit支持RxJava有木有!!!
      http://stackoverflow.com/questions/16902716/comparison-of-android-networking-libraries-okhttp-retrofit-volley#
  • 2.简介

    • 1)retrofit的特点是使用清晰简单的接口,非常方便。
    • 2)网络请求复杂,嵌套请求多,团队技术水平高,可以用retrofit+okhttp+RxAndroid,对于目前的我而言其实是有挑战难度的,但是还是要自学
    • 3)如果项目比较新,并且你想学习使用rxjava,那么推荐retrofit+okhttp配合使用,代码量少了很多很多,写起来很爽,但是有一点需要注意,retrofit没有网络缓存
    • 4)首先Retrofit与okhttp是同一家公司开发出来的,不同之处在与Retrofit是用注解实现了
    • 5)可有使用Glide、Retrofit、Dragger2和Rxjava,okHttp四个框架一起来搭建
    • 6)首先你要知道retrofit它是一个类型安全的网络请求库,Retrofit 把REST API返回的数据转化为Java对象方便操作。 那么你的api是否遵守rest规范
    • 7)简化了网络请求流程,同时自己内部对OkHtttp客户端做了封装
    • 8)retrofit是REST安卓客户端请求库。使用retrofit可以进行GET,POST,PUT,DELETE等请求方式
  • 3.含义
    • 1)需要与web service通信的时候,我们使用retrofit
    • 2)A type-safe HTTP client for Android and Java是一个类型安全的http client库
    • 3)类型安全代码指访问被授权可以访问的内存位置,类型安全代码不能从其他对象的私有字段读取值。它只从定义完善的允许方式访问类型才能读取。类型安全的代码具备定义良好的数据类型。
  • 4.步骤
    • 1)URL拼接:
//Retrofit 在初始化的时候,需要指定一个baseUrl。
private static Retrofit.Builder mBuilder = new Retrofit.Builder()
      .baseUrl("http://192.168.0.102/")
      .addConverterFactory(GsonConverterFactory.create());
    • 2)在我们定义请求的接口时,会传入具体的接口的地址(Endpoint)
/*Retrofit会帮我们完成拼接,最后的URL是
http://192.168.0.102/index.php?c=User&m=getUser
需要注意的是baseUrl必须以”/”结尾
Base URL: http://example.com/api/
Endpoint: foo/bar/
Result: http://example.com/api/foo/bar/
    Endpoint可以为完整的URL:
Endpoint: https://github.com/square/retrofit/
    Retrofit还支持我们在调用时,传入URL*/
@GET("index.php?c=User&m=getUser")
Call<List<User>> getUser();

@GET
Call<List<User>> getUser2(@Url String url);
Call<List<User>> call=userClient.getUser2("http://www.jiangxu.online/index.php?c=User&m=getUser");
  • 5.分类
    • 一.Get查询参数
      1)客户端往服务端传递数据的方式:查询参数,比如我们需要传一个id给服务端,【传单值】那么URL可能是这样的:
      https://api.example.com/tasks?id=123
      Retrofit 定义实现查询参数:
public interface TaskService {
    @GET("/tasks")
    Call<Task> getTask(@Query("id") long taskId);
}

方法getTask需要传入taskId,这个参数会被映射到@Query(“id”)中的id中,最后的URL会变成这样:/tasks?id=

public interface TaskService {
// 1.定义一个任务服务接口
    @GET("/tasks")
// 2.@传数据的方式,声明一个签名方法,参数中@query具体查询参数
    Call<List<Task>> getTask(@Query("id") List<Long> taskIds);
}
public interface TaskService {
    @GET("/tasks")
    Call<List<Task>> getTasks(@Query("sort") String order);
}

那么,在我们不想添加排序控制的时候,我们可以传入null,Retrofit 会忽略值为null的参数。
service.getTasks(null);
需要注意的是,可忽略参数的参数类型不能是int, float, long这些基本类型,应该用Integer, Float, Long来代替。

  • 6.Post 提交参数
    • 1)Retrofit Post方式提交表单形式的参数需要添加标记@FormUrlEncoded,通过@Field注释添加键值对。
    • 2)接口定义:【在参数前添加注释】
public interface UserClient {
    @FormUrlEncoded
    @POST("/index.php?c=User&m=login")
    Call<List<User>> login(@Field("phone") String phone, @Field("password") String password);
}
    • 3)客户端调用:
private void login() {
    UserClient userClient = ServiceGenerator.createService(UserClient.class);
    Call<List<User>> call = userClient.login("13695378745","123456");
    call.enqueue(new Callback<List<User>>() {
    });
}
  • 7.Post 提交JSON数据
    • 1)接口定义:
public interface TaskService {
    @POST("/tasks")
    Call<Task> createTask(@Body Task task);
}
  • 2)传递实体需要有Model:
public class Task {
    private long id;
    private String text;

    public Task() {}
    public Task(long id, String text) {
        this.id = id;
        this.text = text;
    }
}
  • 3)客户端调用:
Task task = new Task(1, "my task title");
Call<Task> call = taskService.createTask(task);
call.enqueue(new Callback<Task>() {}); 
    • 4)这样,服务端得到的是JOSN数据:
{
    "id": 1,
    "text": "my task title"
}
  • 8.同步请求和异步请求,异步的post/json处理方式,至于其他部分以后有时间,有你需求了再来深入研究
TaskService taskService = ServiceGenerator.createService(TaskService.class);
Call<List<Task>> call = taskService.getTasks();
call.enqueue(new Callback<List<Task>>() {
@Override
public void onResponse(Call<List<Task>> call, Response<List<Task>> response) {
        if (response.isSuccess()) {
        // tasks available
        } else {
        // error response, no access to resource?
        }
        }

@Override
public void onFailure(Call<List<Task>> call, Throwable t) {
        // something went completely south (like no internet connection)
        Log.d("Error", t.getMessage());
        }
        }
/*异步请求实现了一个CallBack,包含了两个回调方法:onResponse和 onFailure,在onResponse中我们可以拿到我们需要的实体数据,在onFailure中,可以拿到错误的Log*/
  • 9例子一
    • 1)步骤:首先是导入Retrofit包。
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22.0.0'
    compile 'com.squareup.retrofit:retrofit:1.9.0'
}

{
errNum: 0,
errMsg: "success",
retData: {
   city: "北京", //城市
   pinyin: "beijing", //城市拼音
   citycode: "101010100",  //城市编码   
   date: "15-02-11", //日期
   time: "11:00", //发布时间
   postCode: "100000", //邮编
   longitude: 116.391, //经度
   latitude: 39.904, //维度
   altitude: "33", //海拔 
   weather: "晴",  //天气情况
   temp: "10", //气温
   l_tmp: "-4", //最低气温
   h_tmp: "10", //最高气温
   WD: "无持续风向",  //风向
   WS: "微风(<10m/h)", //风力
   sunrise: "07:12", //日出时间
   sunset: "17:44" //日落时间
  }    
}


public class Result {
    private String errNum;
    private String errMsg;
    private WeatherData retData;

    public void setErrNum(String errNum) {
        this.errNum = errNum;
    }

    public void setErrMsg(String errMsg) {
        this.errMsg = errMsg;
    }

    public WeatherData getRetData() {
        return retData;
    }

    public void setRetData(WeatherData retData) {
        this.retData = retData;
    }

    public String getErrNum() {
        return errNum;
    }

    public String getErrMsg() {
        return errMsg;
    }


}

public class WeatherData {

    private String city; //城市
    private String pinyin;//城市拼音
    private String citycode;  //城市编码
    private String date; //日期
    private String time;//发布时间
    private String postCode; //邮编
    private String longitude;//经度
    private String latitude; //维度
    private String altitude;//海拔
    private String weather; //天气情况
    private String temp; //气温
    private String l_tmp; //最低气温
    private String h_tmp; //最高气温
    private String WD;     //风向
    private String WS; //风力
    private String sunrise;//日出时间
    private String sunset;//日落时间

//setter和getter就不贴了

}
    • 3)新建一个MyService的接口,并采用异步获取的方式。增加Callback< Result > cb
import retrofit.Callback;
import retrofit.http.GET;
import retrofit.http.Query;

public interface MyService {
    // URI:http://apistore.baidu.com/microservice/weather?citypinyin=beijing

    @GET("/microservice/weather")
    void getResult(@Query("citypinyin") String citypinyin, Callback<Result> cb);

}
    • 4)使用RestAdapter来实例化MyService
import retrofit.RestAdapter;

public class MyRestClient {

    private static String API_URL = "http://apistore.baidu.com";

    public static MyService getService() {
        RestAdapter restAdapter = new RestAdapter.Builder()
                .setEndpoint(API_URL)//设置站点路径
                .setLogLevel(RestAdapter.LogLevel.FULL)//设置log的级别
                .build();

        MyService myService = restAdapter.create(MyService.class);

        return myService;
    }

}
    • 5)系统调用如下:
    @Override
    public void onStart()
    {
        super.onStart();
        MyRestClient.getService().getResult("beijing",new Callback<Result>() {
            @Override
            public void success(Result result, Response response) {
                Log.i("",result.getRetData().getDate());
            }

            @Override
            public void failure(RetrofitError error) {

            }
        });

    }
    • 6)添加网络访问权限
<uses-permission android:name="android.permission.INTERNET"></uses-permission>

具体参考http://blog.csdn.net/jeejoy/article/details/45363681
值得一提的是:如果收到的json格式数据中包含对象,则建立一个该对象模型类,还有一个是response响应结果类,包含所有内容,并持有对象的引用。

  • 10例子二
    • 1)添加依赖:retrofit2.0它依赖于OkHttp,而且这部分也不再支持替换。在这里我们也不需要显示的导入okHttp,在retrofit中已经导入okhttp3。
<dependency>
  <groupId>com.squareup.retrofit2</groupId>
  <artifactId>retrofit</artifactId>
  <version>2.0.1</version>
</dependency>

<dependency>
  <groupId>com.squareup.okhttp3</groupId>
  <artifactId>mockwebserver</artifactId>
  <scope>test</scope>
</dependency>

compile 'com.squareup.retrofit2:retrofit:2.0.1'

参考官网:https://github.com/square/retrofit

    • 2)至少java7和Android2.3,需要添加访问网络的权限。
<uses-permission android:name="android.permission.INTERNET"/>
    • 3)创建API接口:在retrofit中通过一个Java接口作为http请求的api接口。
public interface GitHubApi {
//  改为post请求
    @GET("repos/{owner}/{repo}/contributors")
    Call<ResponseBody> contributorsBySimpleGetCall(@Path("owner") String owner, @Path("repo") String repo);
}
    • 4)创建retrofit实例:
      在这里baseUrl是在创建retrofit实例的时候定义的,我们也可以在API接口中定义完整的url。在这里建议在创建baseUrl中以”/”结尾,在API中不以”/”开头和结尾。
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com/")
        .build();
    • 5)调用API接口:在调用API接口请求后,获得一个json字符串,通过Gson进行解析,获得login以及contributions。
GitHubApi repo = retrofit.create(GitHubApi.class);

    Call<ResponseBody> call = repo.contributorsBySimpleGetCall(mUserName, mRepo);
call.enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
        try {
            Gson gson = new Gson();
            ArrayList<Contributor> contributorsList = gson.fromJson(response.body().string(), new TypeToken<List<Contributor>>(){}.getType());
            for (Contributor contributor : contributorsList){
                Log.d("login",contributor.getLogin());
                Log.d("contributions",contributor.getContributions()+"");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {

    }
});

call.cancel();//取消请求,我们可以终止一个请求。终止操作是对底层的httpclient执行cancel操作。即使是正在执行的请求,也能够立即终止

    • 7)另外:增加日志信息
      在retrofit2.0中是没有日志功能的。但是retrofit2.0中依赖OkHttp,所以也就能够通过OkHttp中的interceptor来实现实际的底层的请求和响应日志。在这里我们需要修改上一个retrofit实例,为其自定自定义的OkHttpClient。
    • 8)添加请求头,我们可以通过@Headers来添加请求头。
@Headers({
        "Accept: application/vnd.github.v3.full+json",
        "User-Agent: RetrofitBean-Sample-App",
        "name:ljd"
})
@GET("repos/{owner}/{repo}/contributors")
Call<List<Contributor>> contributorsAndAddHeader(@Path("owner") String owner,@Path("repo") String repo);        
  • 六. 更多细节
    1)Retrofit网络请求有异步的方式,不需要配合Asynctask,直接处理结果就行,callback已经转回到主线程了。与AsyncTask没有任何关系。

  • 7.Retrofit 1 特性

    • 1)定义请求:Retrofit 可以利用接口,方法和注解参数(parameter annotations)来声明式定义一个请求应该如何被创建
      Demo:请求 GitHub API
    • 2)自定义不同的client,不仅仅只是 Apache 的 HTTP client/URL connection/OkHttp 就是一个方法:setClient( )的使用
    • 3)序列化也是可以自定义,方法setConverter(),默认是使用Gson
    • 4)数据交换协议的自定义,protocol buffer/ Google 的 protobuf/ XML 协议的转换,但是很折腾,完全没有必要
    • 5)发送请求的方法:同步/异步,区别就在于异步发送要在最后一个参数上声明一个 callback 回调函数,多了一个参数。

    • 6)支持 RxJava
  • 2.1.0版本的缺点

    • 1)为了支持可替换的功能模块,我们必须嵌套大量的组件,类的数量极多以至于成为了一个痛处,一方面是因为整个库非常的脆弱,还有就是因为我们无法修改公开的 API 接口。
    • 2)如果你想要操作某次请求返回的数据,比如说返回的 Header 部分或者 URL,你又同时想要操作序列化后的数据部分,这是 Retrofit 1.0 上是不可能实现的。

      替代方案:在上面的这个 GitHub 的例子里,我们返回了一个 contributor 的列表,你可以用不同的 converter 去做反序列化。然而,如果说你要读取一个 reponse 的 header 部分。除非你设置一个 endpoint 来接管这个 reponse,不然你没有办法去读取这个 response。 由于 response header 数据里并没有反序列化后的对象,如果不做反序列化操作的话,那你也就无法拿到 contributor 对象了。
    • 3)在某些场景下既需要异步的调用,又需要同步的调用。在 Retrofit 1.0 里,你必须得声明两次这个方法


  • 3.2.0版本

    • 1)延用OkHttp的call类:Retrofit 2 里也多了一个 call 方法。语法和 OkHttp 基本一模一样,唯一不同是这个函数知道如何做数据的反序列化。它知道如何将 HTTP 响应转换成对象。
    • 2)使用方法:每一个 call 对象实例只能被用一次,所以说 request 和 response 都是一一对应的。你其实可以通过 Clone 方法来创建一个一模一样的实例,这个开销是很小的。比如说:你可以在每次决定发请求前 clone 一个之前的实例。
    • 3) 同时支持了在一个类型中的同步和异步。同时,一个请求也可以被真正地终止。终止操作会对底层的 http client 执行 cancel 操作。即便是正在执行的请求,也能立即切断。
    • 4)Parameterized Response Object:参数化的 Response 类型。 Response 对象增加了曾经一直被我们忽略掉的重要元数据:响应码(the reponse code),响应消息(the response message),以及读取相应头(headers)。
    • 5)同时还提供了一个很方便的函数来帮助你判断请求是否成功完成,其实就是检查了下响应码是不是 200。然后就拿到了响应的 body 部分,另外有一个单独的方法获取 error body。基本上就是出现一个返回码,然后调用相对应的函数的。只有当响应成功以后,我们会去做反序列化操作,然后将反序列化的结果放到 body 回调中去。如果出现了返回了网络成功响应(返回码:200)却最终返回 false 的情况,我们实际上是无法判断返回到底是什么的,只能将 ResponseBody(简单封装的了 content-type,length,以及 raw body部分) 类型交给你去处理。

http://square.github.io/retrofit/
http://stackoverflow.com/questions/32965790/retrofit-2-0-how-to-print-the-full-json-response
http://stackoverflow.com/questions/25853071/retrofit-how-to-print-out-response-json
https://realm.io/cn/news/droidcon-jake-wharton-simple-http-retrofit-2/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值