-
Retrofit
2016-01-31 14:48:03 -
retrofit
2016-11-20 23:05:541、Retrofit介绍...在上篇博客中介绍retrofit入门官方介绍地址 http://square.github.io/retrofit/2、流程示意图3、Retrofit代码分析API类中public interface Api { //http://gank.1、Retrofit介绍
http://blog.csdn.net/androidxiaogang/article/details/51725798
在上篇博客中介绍retrofit入门官方介绍地址
http://square.github.io/retrofit/2、流程示意图
1、Retrofit.build()创建Retrofit对象- OkhttpClient 创建OkhttpClient对象,封装的Okhttp请求
- CallBackExecutor 创建CallBackExecutor对象,主要用于请求后的回调
- CallAdapter 创建CallAdapter 对象(适用于Rxjava,Java8,Retrofit,通过泛型识别出adapter)
- Convertor(GsonConverterFactory.create(),返回类型的转换,比如是json,xml,byte流等之类的)
2、ServiceMethod.build()
- createCallAdapter()
- createConvertor
- parseAnnoatation 解析请求参数的注解
3、ExecutorCallBackCall 执行请求
ExecutorCallBackCall<>backCall callAdapter.adapt(OkHttpCall<>)ExecutorCallBackCall.enqueue(new CallBack))
okHttpCall.enqueue(new CallBack){
handler.post(new Runnable){callback.onResponse
})
requestConvertor
okhttp3.Request=okHttpCall.toRequest()
responseConvertor
Retrofit.Response=okHttpCall.toResponse();
}3、Retrofit代码分析
API类中
public interface Api { //http://gank.io/api/data/福利/5/1 @GET("api/data/福利/{pageCount}/{pageIndex}") Call<DataInfo> getData(@Path("pageCount") int pageCount, @Path("pageIndex") int pageIndex); }
请求示例
private void initData(int pages) { //使用retrofit配置api Retrofit retrofit=new Retrofit.Builder() .baseUrl("http://gank.io/") .addConverterFactory(GsonConverterFactory.create()) .build(); Api api =retrofit.create(Api.class); Call<DataInfo> call=api.getData(5,pages); call.enqueue(new Callback<DataInfo>() { @Override public void onResponse(Call<DataInfo> call, Response<DataInfo> response) { arrayList.addAll(response.body().results); adapter.notifyDataSetChanged(); refreshLayout.setRefreshing(false); } @Override public void onFailure(Call<DataInfo> call, Throwable t) { refreshLayout.setRefreshing(false); } }); }
1、构造器模式创建Retrofit对象
Retrofit retrofit=new Retrofit.Builder() .baseUrl("http://gank.io/") .addConverterFactory(GsonConverterFactory.create()) .build();
源码分析
public Retrofit build() { if (baseUrl == null) { throw new IllegalStateException("Base URL required."); } //通过工厂模式创建okhttpclient对象 okhttp3.Call.Factory callFactory = this.callFactory; if (callFactory == null) { //如果为空的话,就创建 callFactory = new OkHttpClient(); } //Executor对象,执行后返回,在主线程中(相当于handler) Executor callbackExecutor = this.callbackExecutor; if (callbackExecutor == null) { callbackExecutor = platform.defaultCallbackExecutor(); } //把adapter添加到Call adapter中 // Make a defensive copy of the adapters and add the default Call adapter. List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories); adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor)); // Make a defensive copy of the converters. List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories); return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories, callbackExecutor, validateEagerly); } }
然后走了callbackExecutor,在这callbackExecutor中异步请求,然后
//发起enqueue异步请求,然后通过callbackExecutor中Runnable把请求的结果回调到主线程中 @Override public void enqueue(final Callback<T> callback) { if (callback == null) throw new NullPointerException("callback == null"); delegate.enqueue(new Callback<T>() { //callbackExecutor请求返回结果的回调 @Override public void onResponse(final Call<T> call, final Response<T> response) { callbackExecutor.execute(new Runnable() { @Override public void run() { if (delegate.isCanceled()) { // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation. callback.onFailure(call, new IOException("Canceled")); } else { callback.onResponse(call, response); } } }); } //callbackExecutor失败的回调 @Override public void onFailure(final Call<T> call, final Throwable t) { callbackExecutor.execute(new Runnable() { @Override public void run() { callback.onFailure(call, t); } }); } }); }
2、请求参数的封装
通过上面得到retrofit对象后,然后进行请求参数封装
Api api =retrofit.create(Api.class);
源码分析
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); } //把http 请求接口中的参数,转换成真正的http call请求 ServiceMethod serviceMethod = loadServiceMethod(method); OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.callAdapter.adapt(okHttpCall); } }); }
然后serviceMethod,通过注解配置http请求
3、通过注解配置http请求(路径,参数)
请求示例代码
public interface Api { //http://gank.io/api/data/福利/5/1 @GET("api/data/福利/{pageCount}/{pageIndex}") Call<DataInfo> getData(@Path("pageCount") int pageCount, @Path("pageIndex") int pageIndex); }
通过上面的serviceMethod,把我们配置的所有http请求,封装到http call中
4、发送请求
在主线程中的方法回调,
call.enqueue(new Callback<DataInfo>() { @Override public void onResponse(Call<DataInfo> call, Response<DataInfo> response) { arrayList.addAll(response.body().results); adapter.notifyDataSetChanged(); refreshLayout.setRefreshing(false); } @Override public void onFailure(Call<DataInfo> call, Throwable t) { refreshLayout.setRefreshing(false); } });
源码分析
public interface Call<T> extends Cloneable { /** * 同步的发送请求和相应 * */ Response<T> execute() throws IOException; /** *异步的发送请求和相应 * */ void enqueue(Callback<T> callback); /** * 如果已经发送请求了,返回true */ boolean isExecuted(); /** * 取消请求 */ void cancel(); /* * 请求是否取消 */ boolean isCanceled(); /** *创建一个新的请求call,即使它已经存在了 */ Call<T> clone(); /** 发送原始的http请求 */ Request request(); }
4、retrofit中的设计思想
1、构建器模式
将复杂的对象构造它的部件创建相分离,android中很多都使用构建器模式,比如dialog弹窗
public interface Builder { void buildCarWheel() ; void buildSteeringWheel() ; void buildEngine() ; void buildCarFrame() ; Car getCar() ; }
2、工厂模式
工厂模式就相当于创建实例对象的new
在retrofit中创建,在这工厂的作用只是创建okhttpclient(可能拓展到httpurlconnection,httpclient)okhttp3.Call.Factory callFactory = this.callFactory; if (callFactory == null) { callFactory = new OkHttpClient(); }
3、代理模式
静态代理:由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理:在程序运行时,运用反射动态创建在retrofit中运用动态代理的方式,来创建请求的类(类中的是普通retrofit请求,或者rxjava请求)
另外(动态代理是AOP,面向切面编程的核心,事实上spring的Aop也是建立在java的动态代理机制之上的。要理解spring,就要先理解java的动态代理机制。)4、适配器模式
要将所有的适配给CallAdapter就需要不同的适配器(接头)
(RxJavaCallAapter,Java8Adapter,AndroidCallAdapter) -
这是一份很详细的 Retrofit 2.0 使用教程(含实例讲解)
2017-06-26 08:35:38前言 在Andrroid开发中,网络请求十分常用 而在Android网络请求库中,Retrofit是当下... 如果对Retrofit v2.0的源码感兴趣,可看文章:Android:手把手带你深入剖析 Retrofit 2.0 源码 目录封装了 数据转换、线程切换的操作
步骤7:处理服务器返回的数据
接下来,我们一步步进行讲解。
步骤1:添加Retrofit库的依赖
1. 在
Gradle
加入Retrofit
库的依赖由于
Retrofit
是基于OkHttp
,所以还需要添加OkHttp
库依赖build.gradle
dependencies { compile 'com.squareup.retrofit2:retrofit:2.0.2' // Retrofit库 compile 'com.squareup.okhttp3:okhttp:3.1.2' // Okhttp库 }
2. 添加 网络权限
AndroidManifest.xml<uses-permission android:name="android.permission.INTERNET"/>
步骤2:创建 接收服务器返回数据 的类
Reception.java
public class Reception { ... // 根据返回数据的格式和数据解析方式(Json、XML等)定义 // 下面会在实例进行说明 }
步骤3:创建 用于描述网络请求 的接口
- Retrofit将 Http请求 抽象成 Java接口:采用 注解 描述网络请求参数 和配置网络请求参数
- 用 动态代理 动态 将该接口的注解“翻译”成一个 Http 请求,最后再执行 Http 请求
- 注:接口中的每个方法的参数都需要使用注解标注,否则会报错
GetRequest_Interface.interface
public interface GetRequest_Interface { @GET("openapi.do?keyfrom=Yanzhikai&key=2032414398&type=data&doctype=json&version=1.1&q=car") Call<Translation> getCall(); // @GET注解的作用:采用Get方法发送网络请求 // getCall() = 接收网络请求数据的方法 // 其中返回类型为Call<*>,*是接收数据的类(即上面定义的Translation类) // 如果想直接获得Responsebody中的内容,可以定义网络请求返回值为Call<ResponseBody> }
下面详细介绍Retrofit 网络请求接口 的注解类型。
注解类型
注解说明
第一类:网络请求方法
详细说明:
a. @GET、@POST、@PUT、@DELETE、@HEAD
以上方法分别对应 HTTP中的网络请求方式public interface GetRequest_Interface { @GET("openapi.do?keyfrom=Yanzhikai&key=2032414398&type=data&doctype=json&version=1.1&q=car") Call<Translation> getCall(); // @GET注解的作用:采用Get方法发送网络请求 // getCall() = 接收网络请求数据的方法 // 其中返回类型为Call<*>,*是接收数据的类(即上面定义的Translation类) }
此处特意说明URL的组成:Retrofit把 网络请求的URL 分成了两部分设置:
// 第1部分:在网络请求接口的注解设置 @GET("openapi.do?keyfrom=Yanzhikai&key=2032414398&type=data&doctype=json&version=1.1&q=car") Call<Translation> getCall(); // 第2部分:在创建Retrofit实例时通过.baseUrl()设置 Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://fanyi.youdao.com/") //设置网络请求的Url地址 .addConverterFactory(GsonConverterFactory.create()) //设置数据解析器 .build(); // 从上面看出:一个请求的URL可以通过 替换块 和 请求方法的参数 来进行动态的URL更新。 // 替换块是由 被{}包裹起来的字符串构成 // 即:Retrofit支持动态改变网络请求根目录
- 网络请求的完整 Url =在创建Retrofit实例时通过.baseUrl()设置 +网络请求接口的注解设置(下面称 “path“ )
- 具体整合的规则如下:
建议采用第三种方式来配置,并尽量使用同一种路径形式。
b. @HTTP
- 作用:替换**@GET、@POST、@PUT、@DELETE、@HEAD**注解的作用 及 更多功能拓展
- 具体使用:通过属性method、path、hasBody进行设置
public interface GetRequest_Interface { /** * method:网络请求的方法(区分大小写) * path:网络请求地址路径 * hasBody:是否有请求体 */ @HTTP(method = "GET", path = "blog/{id}", hasBody = false) Call<ResponseBody> getCall(@Path("id") int id); // {id} 表示是一个变量 // method 的值 retrofit 不会做处理,所以要自行保证准确 }
第二类:标记
a. @FormUrlEncoded
- 作用:表示发送form-encoded的数据
每个键值对需要用@Filed来注解键名,随后的对象需要提供值。
b. @Multipart
- 作用:表示发送form-encoded的数据(适用于 有文件 上传的场景)
每个键值对需要用@Part来注解键名,随后的对象需要提供值。
具体使用如下:
GetRequest_Interfacepublic interface GetRequest_Interface { /** *表明是一个表单格式的请求(Content-Type:application/x-www-form-urlencoded) * <code>Field("username")</code> 表示将后面的 <code>String name</code> 中name的取值作为 username 的值 */ @POST("/form") @FormUrlEncoded Call<ResponseBody> testFormUrlEncoded1(@Field("username") String name, @Field("age") int age); /** * {@link Part} 后面支持三种类型,{@link RequestBody}、{@link okhttp3.MultipartBody.Part} 、任意类型 * 除 {@link okhttp3.MultipartBody.Part} 以外,其它类型都必须带上表单字段({@link okhttp3.MultipartBody.Part} 中已经包含了表单字段的信息), */ @POST("/form") @Multipart Call<ResponseBody> testFileUpload1(@Part("name") RequestBody name, @Part("age") RequestBody age, @Part MultipartBody.Part file); } // 具体使用 GetRequest_Interface service = retrofit.create(GetRequest_Interface.class); // @FormUrlEncoded Call<ResponseBody> call1 = service.testFormUrlEncoded1("Carson", 24); // @Multipart RequestBody name = RequestBody.create(textType, "Carson"); RequestBody age = RequestBody.create(textType, "24"); MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", "test.txt", file); Call<ResponseBody> call3 = service.testFileUpload1(name, age, filePart);
第三类:网络请求参数
详细说明
a. @Header & @Headers
- 作用:添加请求头 &添加不固定的请求头
- 具体使用如下:
// @Header @GET("user") Call<User> getUser(@Header("Authorization") String authorization) // @Headers @Headers("Authorization: authorization") @GET("user") Call<User> getUser() // 以上的效果是一致的。 // 区别在于使用场景和使用方式 // 1. 使用场景:@Header用于添加不固定的请求头,@Headers用于添加固定的请求头 // 2. 使用方式:@Header作用于方法的参数;@Headers作用于方法
b. @Body
- 作用:以
Post
方式 传递 自定义数据类型 给服务器 - 特别注意:如果提交的是一个Map,那么作用相当于
@Field
不过Map要经过
FormBody.Builder
类处理成为符合 Okhttp 格式的表单,如:FormBody.Builder builder = new FormBody.Builder(); builder.add("key","value");
c. @Field & @FieldMap
- 作用:发送 Post请求 时提交请求的表单字段
- 具体使用:与
@FormUrlEncoded
注解配合使用
public interface GetRequest_Interface { /** *表明是一个表单格式的请求(Content-Type:application/x-www-form-urlencoded) * <code>Field("username")</code> 表示将后面的 <code>String name</code> 中name的取值作为 username 的值 */ @POST("/form") @FormUrlEncoded Call<ResponseBody> testFormUrlEncoded1(@Field("username") String name, @Field("age") int age); /** * Map的key作为表单的键 */ @POST("/form") @FormUrlEncoded Call<ResponseBody> testFormUrlEncoded2(@FieldMap Map<String, Object> map); } // 具体使用 // @Field Call<ResponseBody> call1 = service.testFormUrlEncoded1("Carson", 24); // @FieldMap // 实现的效果与上面相同,但要传入Map Map<String, Object> map = new HashMap<>(); map.put("username", "Carson"); map.put("age", 24); Call<ResponseBody> call2 = service.testFormUrlEncoded2(map);
d. @Part & @PartMap
- 作用:发送 Post请求 时提交请求的表单字段
与@Field的区别:功能相同,但携带的参数类型更加丰富,包括数据流,所以适用于 有文件上传 的场景
- 具体使用:与
@Multipart
注解配合使用
public interface GetRequest_Interface { /** * {@link Part} 后面支持三种类型,{@link RequestBody}、{@link okhttp3.MultipartBody.Part} 、任意类型 * 除 {@link okhttp3.MultipartBody.Part} 以外,其它类型都必须带上表单字段({@link okhttp3.MultipartBody.Part} 中已经包含了表单字段的信息), */ @POST("/form") @Multipart Call<ResponseBody> testFileUpload1(@Part("name") RequestBody name, @Part("age") RequestBody age, @Part MultipartBody.Part file); /** * PartMap 注解支持一个Map作为参数,支持 {@link RequestBody } 类型, * 如果有其它的类型,会被{@link retrofit2.Converter}转换,如后面会介绍的 使用{@link com.google.gson.Gson} 的 {@link retrofit2.converter.gson.GsonRequestBodyConverter} * 所以{@link MultipartBody.Part} 就不适用了,所以文件只能用<b> @Part MultipartBody.Part </b> */ @POST("/form") @Multipart Call<ResponseBody> testFileUpload2(@PartMap Map<String, RequestBody> args, @Part MultipartBody.Part file); @POST("/form") @Multipart Call<ResponseBody> testFileUpload3(@PartMap Map<String, RequestBody> args); } // 具体使用 MediaType textType = MediaType.parse("text/plain"); RequestBody name = RequestBody.create(textType, "Carson"); RequestBody age = RequestBody.create(textType, "24"); RequestBody file = RequestBody.create(MediaType.parse("application/octet-stream"), "这里是模拟文件的内容"); // @Part MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", "test.txt", file); Call<ResponseBody> call3 = service.testFileUpload1(name, age, filePart); ResponseBodyPrinter.printResponseBody(call3); // @PartMap // 实现和上面同样的效果 Map<String, RequestBody> fileUpload2Args = new HashMap<>(); fileUpload2Args.put("name", name); fileUpload2Args.put("age", age); //这里并不会被当成文件,因为没有文件名(包含在Content-Disposition请求头中),但上面的 filePart 有 //fileUpload2Args.put("file", file); Call<ResponseBody> call4 = service.testFileUpload2(fileUpload2Args, filePart); //单独处理文件 ResponseBodyPrinter.printResponseBody(call4); }
e. @Query和@QueryMap
- 作用:用于
@GET
方法的查询参数(Query = Url 中 ‘?’ 后面的 key-value)
如:url = http://www.println.net/?cate=android,其中,Query = cate
- 具体使用:配置时只需要在接口方法中增加一个参数即可:
@GET("/") Call<String> cate(@Query("cate") String cate); } // 其使用方式同 @Field与@FieldMap,这里不作过多描述
f. @Path
- 作用:URL地址的缺省值
- 具体使用:
public interface GetRequest_Interface { @GET("users/{user}/repos") Call<ResponseBody> getBlog(@Path("user") String user ); // 访问的API是:https://api.github.com/users/{user}/repos // 在发起请求时, {user} 会被替换为方法的第一个参数 user(被@Path注解作用) }
g. @Url
- 作用:直接传入一个请求的 URL变量 用于URL设置
- 具体使用:
public interface GetRequest_Interface { @GET Call<ResponseBody> testUrlAndQuery(@Url String url, @Query("showAll") boolean showAll); // 当有URL注解时,@GET传入的URL就可以省略 // 当GET、POST...HTTP等方法中没有设置Url时,则必须使用 {@link Url}提供 }
汇总
步骤4:创建 Retrofit 实例
Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://fanyi.youdao.com/") // 设置网络请求的Url地址 .addConverterFactory(GsonConverterFactory.create()) // 设置数据解析器 .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // 支持RxJava平台 .build();
a. 关于数据解析器(Converter)
- Retrofit支持多种数据解析方式
- 使用时需要在Gradle添加依赖
数据解析器 Gradle依赖 Gson com.squareup.retrofit2:converter-gson:2.0.2 Jackson com.squareup.retrofit2:converter-jackson:2.0.2 Simple XML com.squareup.retrofit2:converter-simplexml:2.0.2 Protobuf com.squareup.retrofit2:converter-protobuf:2.0.2 Moshi com.squareup.retrofit2:converter-moshi:2.0.2 Wire com.squareup.retrofit2:converter-wire:2.0.2 Scalars com.squareup.retrofit2:converter-scalars:2.0.2 b. 关于网络请求适配器(CallAdapter)
- Retrofit支持多种网络请求适配器方式:guava、Java8和rxjava
使用时如使用的是
Android
默认的CallAdapter
,则不需要添加网络请求适配器的依赖,否则则需要按照需求进行添加
Retrofit 提供的CallAdapter
- 使用时需要在Gradle添加依赖:
网络请求适配器 Gradle依赖 guava com.squareup.retrofit2:adapter-guava:2.0.2 Java8 com.squareup.retrofit2:adapter-java8:2.0.2 rxjava com.squareup.retrofit2:adapter-rxjava:2.0.2 步骤5:创建 网络请求接口实例
// 创建 网络请求接口 的实例 GetRequest_Interface request = retrofit.create(GetRequest_Interface.class); //对 发送请求 进行封装 Call<Reception> call = request.getCall();
步骤6:发送网络请求(异步 / 同步)
封装了 数据转换、线程切换的操作
//发送网络请求(异步) call.enqueue(new Callback<Translation>() { //请求成功时回调 @Override public void onResponse(Call<Translation> call, Response<Translation> response) { //请求处理,输出结果 response.body().show(); } //请求失败时候的回调 @Override public void onFailure(Call<Translation> call, Throwable throwable) { System.out.println("连接失败"); } }); // 发送网络请求(同步) Response<Reception> response = call.execute();
步骤7:处理返回数据
通过
response
类的body()
对返回的数据进行处理//发送网络请求(异步) call.enqueue(new Callback<Translation>() { //请求成功时回调 @Override public void onResponse(Call<Translation> call, Response<Translation> response) { // 对返回数据进行处理 response.body().show(); } //请求失败时候的回调 @Override public void onFailure(Call<Translation> call, Throwable throwable) { System.out.println("连接失败"); } }); // 发送网络请求(同步) Response<Reception> response = call.execute(); // 对返回数据进行处理 response.body().show();
4. 实例讲解
接下来,我将用两个实例分别对 Retrofit GET方式 和 POST方式进行 网络请求 讲解。
4.1 实例1
- 实现功能:将中文翻译成英文
- 实现方案:采用
Get
方法对 金山词霸API 发送网络请求
采用
Gson
进行数据解析- 步骤说明
步骤1:添加Retrofit库的依赖
步骤2:创建 接收服务器返回数据 的类
步骤3:创建 用于描述网络请求 的接口
步骤4:创建 Retrofit 实例
步骤5:创建 网络请求接口实例 并 配置网络请求参数
步骤6:发送网络请求(采用最常用的异步方式)封装了 数据转换、线程切换的操作
步骤7:处理服务器返回的数据
接下来,我们一步步进行讲解。
- 具体使用
步骤1:添加Retrofit库的依赖
1. 在
Gradle
加入Retrofit
库的依赖由于
Retrofit
是基于OkHttp
,所以还需要添加OkHttp
库依赖build.gradle
dependencies { compile 'com.squareup.retrofit2:retrofit:2.0.2' // Retrofit库 compile 'com.squareup.okhttp3:okhttp:3.1.2' // Okhttp库 }
2. 添加 网络权限
AndroidManifest.xml<uses-permission android:name="android.permission.INTERNET"/>
步骤2:创建 接收服务器返回数据 的类
- 金山词霸API 的数据格式说明如下:
// URL模板 http://fy.iciba.com/ajax.php // URL实例 http://fy.iciba.com/ajax.php?a=fy&f=auto&t=auto&w=hello%20world // 参数说明: // a:固定值 fy // f:原文内容类型,日语取 ja,中文取 zh,英语取 en,韩语取 ko,德语取 de,西班牙语取 es,法语取 fr,自动则取 auto // t:译文内容类型,日语取 ja,中文取 zh,英语取 en,韩语取 ko,德语取 de,西班牙语取 es,法语取 fr,自动则取 auto // w:查询内容
- 根据 金山词霸API 的数据格式,创建 接收服务器返回数据 的类:
Translation.java
public class Translation { private int status; private content content; private static class content { private String from; private String to; private String vendor; private String out; private int errNo; } //定义 输出返回数据 的方法 public void show() { System.out.println(status); System.out.println(content.from); System.out.println(content.to); System.out.println(content.vendor); System.out.println(content.out); System.out.println(content.errNo); } }
步骤3:创建 用于描述网络请求 的接口
采用 注解 描述 网络请求参数。
GetRequest_Interface.javapublic interface GetRequest_Interface { @GET("ajax.php?a=fy&f=auto&t=auto&w=hello%20world") Call<Translation> getCall(); // 注解里传入 网络请求 的部分URL地址 // Retrofit把网络请求的URL分成了两部分:一部分放在Retrofit对象里,另一部分放在网络请求接口里 // 如果接口里的url是一个完整的网址,那么放在Retrofit对象里的URL可以忽略 // getCall()是接受网络请求数据的方法 }
接下来的步骤均在GetRequest.java内实现(看注释)
步骤4:创建Retrofit对象
步骤5:创建 网络请求接口 的实例
步骤6:发送网络请求以最常用的 异步请求 为例
步骤7:处理返回数据
GetRequest.java
public class GetRequest extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); request(); // 使用Retrofit封装的方法 } public void request() { //步骤4:创建Retrofit对象 Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://fy.iciba.com/") // 设置 网络请求 Url .addConverterFactory(GsonConverterFactory.create()) //设置使用Gson解析(记得加入依赖) .build(); // 步骤5:创建 网络请求接口 的实例 GetRequest_Interface request = retrofit.create(GetRequest_Interface.class); //对 发送请求 进行封装 Call<Translation> call = request.getCall(); //步骤6:发送网络请求(异步) call.enqueue(new Callback<Translation>() { //请求成功时回调 @Override public void onResponse(Call<Translation> call, Response<Translation> response) { // 步骤7:处理返回的数据结果 response.body().show(); } //请求失败时回调 @Override public void onFailure(Call<Translation> call, Throwable throwable) { System.out.println("连接失败"); } }); } }
由于此处采用了 Gson 解析,所以需要在 Gradle加入依赖
build.gradlecompile 'com.squareup.retrofit2:converter-gson:2.0.2'
运行结果
Demo地址
Carson_Ho的Github:https://github.com/Carson-Ho/RetrofitDemo
4.2 实例2
- 实现的功能:将 英文 翻译成 中文
- 实现方法:采用
Post方法
对 有道API 发送网络请求
采用
Gson
进行数据解析- 使用步骤
步骤1:添加Retrofit库的依赖
步骤2:创建 接收服务器返回数据 的类
步骤3:创建 用于描述网络请求 的接口
步骤4:创建 Retrofit 实例
步骤5:创建 网络请求接口实例 并 配置网络请求参数
步骤6:发送网络请求(采用最常用的异步方式)封装了 数据转换、线程切换的操作
步骤7:处理服务器返回的数据
接下来,我们一步步进行Retrofit的使用。
- 具体使用
步骤1:添加Retrofit库的依赖
1. 在
Gradle
加入Retrofit
库的依赖由于
Retrofit
是基于OkHttp
,所以还需要添加OkHttp
库依赖build.gradle
dependencies { compile 'com.squareup.retrofit2:retrofit:2.0.2' // Retrofit库 compile 'com.squareup.okhttp3:okhttp:3.1.2' // Okhttp库 }
2. 添加 网络权限
AndroidManifest.xml<uses-permission android:name="android.permission.INTERNET"/>
步骤2:创建 接收服务器返回数据 的类
- API 的数据格式说明如下:
// URL http://fanyi.youdao.com/translate // URL实例 http://fanyi.youdao.com/translate?doctype=json&jsonversion=&type=&keyfrom=&model=&mid=&imei=&vendor=&screen=&ssid=&network=&abtest= // 参数说明 // doctype:json 或 xml // jsonversion:如果 doctype 值是 xml,则去除该值,若 doctype 值是 json,该值为空即可 // xmlVersion:如果 doctype 值是 json,则去除该值,若 doctype 值是 xml,该值为空即可 // type:语言自动检测时为 null,为 null 时可为空。英译中为 EN2ZH_CN,中译英为 ZH_CN2EN,日译中为 JA2ZH_CN,中译日为 ZH_CN2JA,韩译中为 KR2ZH_CN,中译韩为 ZH_CN2KR,中译法为 ZH_CN2FR,法译中为 FR2ZH_CN // keyform:mdict. + 版本号 + .手机平台。可为空 // model:手机型号。可为空 // mid:平台版本。可为空 // imei:???。可为空 // vendor:应用下载平台。可为空 // screen:屏幕宽高。可为空 // ssid:用户名。可为空 // abtest:???。可为空 // 请求方式说明 // 请求方式:POST // 请求体:i // 请求格式:x-www-form-urlencoded
- 根据 有道API 的数据格式,创建 接收服务器返回数据 的类:
Translation.java
public class Translation1 { private String type; private int errorCode; private int elapsedTime; private List<List<TranslateResultBean>> translateResult; public String getType() { return type; } public void setType(String type) { this.type = type; } public int getErrorCode() { return errorCode; } public void setErrorCode(int errorCode) { this.errorCode = errorCode; } public int getElapsedTime() { return elapsedTime; } public void setElapsedTime(int elapsedTime) { this.elapsedTime = elapsedTime; } public List<List<TranslateResultBean>> getTranslateResult() { return translateResult; } public void setTranslateResult(List<List<TranslateResultBean>> translateResult) { this.translateResult = translateResult; } public static class TranslateResultBean { /** * src : merry me * tgt : 我快乐 */ public String src; public String tgt; public String getSrc() { return src; } public void setSrc(String src) { this.src = src; } public String getTgt() { return tgt; } public void setTgt(String tgt) { this.tgt = tgt; } } }
步骤3:创建 用于描述网络请求 的接口
采用 注解 描述 网络请求参数。
PostRequest_Interface.java
public interface PostRequest_Interface { @POST("translate?doctype=json&jsonversion=&type=&keyfrom=&model=&mid=&imei=&vendor=&screen=&ssid=&network=&abtest=") @FormUrlEncoded Call<Translation1> getCall(@Field("i") String targetSentence); //采用@Post表示Post方法进行请求(传入部分url地址) // 采用@FormUrlEncoded注解的原因:API规定采用请求格式x-www-form-urlencoded,即表单形式 // 需要配合@Field 向服务器提交需要的字段 }
接下来的步骤均在PostRequest.java内实现(看注释)
步骤4:创建Retrofit对象
步骤5:创建 网络请求接口 的实例
步骤6:发送网络请求以最常用的 异步请求 为例
步骤7:处理返回数据
PostRequest.java
public class PostRequest extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); request(); } public void request() { //步骤4:创建Retrofit对象 Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://fanyi.youdao.com/") // 设置 网络请求 Url .addConverterFactory(GsonConverterFactory.create()) //设置使用Gson解析(记得加入依赖) .build(); // 步骤5:创建 网络请求接口 的实例 PostRequest_Interface request = retrofit.create(PostRequest_Interface.class); //对 发送请求 进行封装(设置需要翻译的内容) Call<Translation1> call = request.getCall("I love you"); //步骤6:发送网络请求(异步) call.enqueue(new Callback<Translation1>() { //请求成功时回调 @Override public void onResponse(Call<Translation1> call, Response<Translation1> response) { // 步骤7:处理返回的数据结果:输出翻译的内容 System.out.println(response.body().getTranslateResult().get(0).get(0).getTgt()); } //请求失败时回调 @Override public void onFailure(Call<Translation1> call, Throwable throwable) { System.out.println("请求失败"); System.out.println(throwable.getMessage()); } }); } }
由于此处采用了 Gson 解析,所以需要在
Gradle
加入依赖
build.gradlecompile 'com.squareup.retrofit2:converter-gson:2.0.2'
运行结果
Demo地址
Carson_Ho的Github:https://github.com/Carson-Ho/RetrofitDemo
5. Retrofit 的拓展使用
- Retrofit的使用场景非常丰富,如支持
RxJava
和Prototocobuff
- 具体设置也非常简单 & 方便:
<-- 主要在创建Retrofit对象中设置 --> Retrofit retrofit = new Retrofit.Builder() .baseUrl(""http://fanyi.youdao.com/"") .addConverterFactory(ProtoConverterFactory.create()) // 支持Prototocobuff解析 .addConverterFactory(GsonConverterFactory.create()) // 支持Gson解析 .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // 支持RxJava .build();
具体关于
RxJava
的使用这里就不展开,请期待下篇关于Rxjava
的文章。6. 总结
- 看完本文,相信你已经非常熟悉
Retrofit 2.0
的使用 - 如果你希望继续阅读
Retrofit 2.0
的源码,请看我写的文章:Android:手把手带你深入剖析 Retrofit 2.0 源码 - 接下来,我将继续分析与 Retrofit 配合使用的 RxJava,有兴趣可以继续关注Carson_Ho的安卓开发笔记
帮顶或评论点赞!因为你的鼓励是我写作的最大动力!
欢迎关注carson_ho的微信公众号
- 在
-
Retrofit用法详解
2016-08-06 23:11:33一、 简介Retrofit是Square公司开发的一款针对Android网络请求的框架,Retrofit2底层基于OkHttp实现的,OkHttp现在已经得到Google官方认可,大量的app都采用OkHttp做网络请求,其源码详见OkHttp Github。 本文全部...###一、 简介
Retrofit是Square公司开发的一款针对Android网络请求的框架,Retrofit2底层基于OkHttp实现的,OkHttp现在已经得到Google官方认可,大量的app都采用OkHttp做网络请求,其源码详见OkHttp Github。
本文全部是在Retrofit2.0+版本基础上论述,所用例子全部来自豆瓣Api
首先先来看一个完整Get请求是如何实现:
-
创建业务请求接口,具体代码如下:
public interface BlueService { @GET("book/search") Call<BookSearchResponse> getSearchBooks(@Query("q") String name, @Query("tag") String tag, @Query("start") int start, @Query("count") int count); }
这里需要稍作说明,@GET注解就表示get请求,@Query表示请求参数,将会以key=value的方式拼接在url后面
-
需要创建一个Retrofit的示例,并完成相应的配置
Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.douban.com/v2/") .addConverterFactory(GsonConverterFactory.create()) .build(); BlueService service = retrofit.create(BlueService.class);
这里的baseUrl就是网络请求URL相对固定的地址,一般包括请求协议(如Http)、域名或IP地址、端口号等,当然还会有很多其他的配置,下文会详细介绍。还有addConverterFactory方法表示需要用什么转换器来解析返回值,GsonConverterFactory.create()表示调用Gson库来解析json返回值,具体的下文还会做详细介绍。
-
调用请求方法,并得到Call实例
Call<BookSearchResponse> call = mBlueService.getSearchBooks("小王子", "", 0, 3);
Call其实在Retrofit中就是行使网络请求并处理返回值的类,调用的时候会把需要拼接的参数传递进去,此处最后得到的url完整地址为
https://api.douban.com/v2/book/search?q=%E5%B0%8F%E7%8E%8B%E5%AD%90&tag=&start=0&count=3
-
使用Call实例完成同步或异步请求
-
同步请求
BookSearchResponse response = call.execute().body();
这里需要注意的是网络请求一定要在子线程中完成,不能直接在UI线程执行,不然会crash
-
异步请求
call.enqueue(new Callback<BookSearchResponse>() { @Override public void onResponse(Call<BookSearchResponse> call, Response<BookSearchResponse> response) { asyncText.setText("异步请求结果: " + response.body().books.get(0).altTitle); } @Override public void onFailure(Call<BookSearchResponse> call, Throwable t) { } });
-
二、如何使用
首先需要在build.gradle文件中引入需要的第三包,配置如下:
compile 'com.squareup.retrofit2:retrofit:2.1.0' compile 'com.squareup.retrofit2:converter-gson:2.1.0' compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
引入完第三包接下来就可以使用Retrofit来进行网络请求了。接下来会对不同的请求方式做进一步的说明。
Get方法
1. @Query
Get方法请求参数都会以key=value的方式拼接在url后面,Retrofit提供了两种方式设置请求参数。第一种就是像上文提到的直接在interface中添加@Query注解,还有一种方式是通过Interceptor实现,直接看如何通过Interceptor实现请求参数的添加。
public class CustomInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); HttpUrl httpUrl = request.url().newBuilder() .addQueryParameter("token", "tokenValue") .build(); request = request.newBuilder().url(httpUrl).build(); return chain.proceed(request); } }
addQueryParameter就是添加请求参数的具体代码,这种方式比较适用于所有的请求都需要添加的参数,一般现在的网络请求都会添加token作为用户标识,那么这种方式就比较适合。
创建完成自定义的Interceptor后,还需要在Retrofit创建client处完成添加
addInterceptor(new CustomInterceptor())
2. @QueryMap
如果Query参数比较多,那么可以通过@QueryMap方式将所有的参数集成在一个Map统一传递,还以上文中的get请求方法为例
public interface BlueService { @GET("book/search") Call<BookSearchResponse> getSearchBooks(@QueryMap Map<String, String> options); }
调用的时候将所有的参数集合在统一的map中即可
Map<String, String> options = new HashMap<>(); map.put("q", "小王子"); map.put("tag", null); map.put("start", "0"); map.put("count", "3"); Call<BookSearchResponse> call = mBlueService.getSearchBooks(options);
3. Query集合
假如你需要添加相同Key值,但是value却有多个的情况,一种方式是添加多个@Query参数,还有一种简便的方式是将所有的value放置在列表中,然后在同一个@Query下完成添加,实例代码如下:
public interface BlueService { @GET("book/search") Call<BookSearchResponse> getSearchBooks(@Query("q") List<String> name); }
最后得到的url地址为
https://api.douban.com/v2/book/search?q=leadership&q=beyond%20feelings
4. Query非必填
如果请求参数为非必填,也就是说即使不传该参数,服务端也可以正常解析,那么如何实现呢?其实也很简单,请求方法定义处还是需要完整的Query注解,某次请求如果不需要传该参数的话,只需填充null即可。
针对文章开头提到的get的请求,加入按以下方式调用
Call<BookSearchResponse> call = mBlueService.getSearchBooks("小王子", null, 0, 3);
那么得到的url地址为
https://api.douban.com/v2/book/search?q=%E5%B0%8F%E7%8E%8B%E5%AD%90&start=0&count=3
5. @Path
如果请求的相对地址也是需要调用方传递,那么可以使用@Path注解,示例代码如下:
@GET("book/{id}") Call<BookResponse> getBook(@Path("id") String id);
业务方想要在地址后面拼接书籍id,那么通过Path注解可以在具体的调用场景中动态传递,具体的调用方式如下:
Call<BookResponse> call = mBlueService.getBook("1003078");
此时的url地址为
https://api.douban.com/v2/book/1003078
@Path可以用于任何请求方式,包括Post,Put,Delete等等
Post请求
1. @field
Post请求需要把请求参数放置在请求体中,而非拼接在url后面,先来看一个简单的例子
@FormUrlEncoded @POST("book/reviews") Call<String> addReviews(@Field("book") String bookId, @Field("title") String title, @Field("content") String content, @Field("rating") String rating);
这里有几点需要说明的
-
@FormUrlEncoded将会自动将请求参数的类型调整为application/x-www-form-urlencoded,假如content传递的参数为Good Luck,那么最后得到的请求体就是
content=Good+Luck
FormUrlEncoded不能用于Get请求
-
@Field注解将每一个请求参数都存放至请求体中,还可以添加encoded参数,该参数为boolean型,具体的用法为
@Field(value = "book", encoded = true) String book
encoded参数为true的话,key-value-pair将会被编码,即将中文和特殊字符进行编码转换
2. @FieldMap
上述Post请求有4个请求参数,假如说有更多的请求参数,那么通过一个一个的参数传递就显得很麻烦而且容易出错,这个时候就可以用FieldMap
@FormUrlEncoded @POST("book/reviews") Call<String> addReviews(@FieldMap Map<String, String> fields);
3. @Body
如果Post请求参数有多个,那么统一封装到类中应该会更好,这样维护起来会非常方便
@FormUrlEncoded @POST("book/reviews") Call<String> addReviews(@Body Reviews reviews); public class Reviews { public String book; public String title; public String content; public String rating; }
其他请求方式
除了Get和Post请求,Http请求还包括Put,Delete等等,用法和Post相似,所以就不再单独介绍了。
上传
上传因为需要用到Multipart,所以需要单独拿出来介绍,先看一个具体上传的例子
首先还是需要新建一个interface用于定义上传方法
public interface FileUploadService { // 上传单个文件 @Multipart @POST("upload") Call<ResponseBody> uploadFile( @Part("description") RequestBody description, @Part MultipartBody.Part file); // 上传多个文件 @Multipart @POST("upload") Call<ResponseBody> uploadMultipleFiles( @Part("description") RequestBody description, @Part MultipartBody.Part file1, @Part MultipartBody.Part file2); }
接下来我们还需要在Activity和Fragment中实现两个工具方法,代码如下:
public static final String MULTIPART_FORM_DATA = "multipart/form-data"; @NonNull private RequestBody createPartFromString(String descriptionString) { return RequestBody.create( MediaType.parse(MULTIPART_FORM_DATA), descriptionString); } @NonNull private MultipartBody.Part prepareFilePart(String partName, Uri fileUri) { File file = FileUtils.getFile(this, fileUri); // 为file建立RequestBody实例 RequestBody requestFile = RequestBody.create(MediaType.parse(MULTIPART_FORM_DATA), file); // MultipartBody.Part借助文件名完成最终的上传 return MultipartBody.Part.createFormData(partName, file.getName(), requestFile); }
好了,接下来就是最终的上传文件代码了
Uri file1Uri = ... // 从文件选择器或者摄像头中获取 Uri file2Uri = ... // 创建上传的service实例 FileUploadService service = ServiceGenerator.createService(FileUploadService.class); // 创建文件的part (photo, video, ...) MultipartBody.Part body1 = prepareFilePart("video", file1Uri); MultipartBody.Part body2 = prepareFilePart("thumbnail", file2Uri); // 添加其他的part RequestBody description = createPartFromString("hello, this is description speaking"); // 最后执行异步请求操作 Call<ResponseBody> call = service.uploadMultipleFiles(description, body1, body2); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { Log.v("Upload", "success"); } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { Log.e("Upload error:", t.getMessage()); } });
三、其他必须知道的事项
1. 添加自定义的header
Retrofit提供了两个方式定义Http请求头参数:静态方法和动态方法,静态方法不能随不同的请求进行变化,头部信息在初始化的时候就固定了。而动态方法则必须为每个请求都要单独设置。
-
静态方法
public interface BlueService { @Headers("Cache-Control: max-age=640000") @GET("book/search") Call<BookSearchResponse> getSearchBooks(@Query("q") String name, @Query("tag") String tag, @Query("start") int start, @Query("count") int count); }
当然你想添加多个header参数也是可以的,写法也很简单
public interface BlueService { @Headers({ "Accept: application/vnd.yourapi.v1.full+json", "User-Agent: Your-App-Name" }) @GET("book/search") Call<BookSearchResponse> getSearchBooks(@Query("q") String name, @Query("tag") String tag, @Query("start") int start, @Query("count") int count); }
此外也可以通过Interceptor来定义静态请求头
public class RequestInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request original = chain.request(); Request request = original.newBuilder() .header("User-Agent", "Your-App-Name") .header("Accept", "application/vnd.yourapi.v1.full+json") .method(original.method(), original.body()) .build(); return chain.proceed(request); } }
添加header参数Request提供了两个方法,一个是header(key, value),另一个是**.addHeader(key, value)**,两者的区别是,header()如果有重名的将会覆盖,而addHeader()允许相同key值的header存在
然后在OkHttp创建Client实例时,添加RequestInterceptor即可
private static OkHttpClient getNewClient(){ return new OkHttpClient.Builder() .addInterceptor(new RequestInterceptor()) .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) .build(); }
-
动态方法
public interface BlueService { @GET("book/search") Call<BookSearchResponse> getSearchBooks( @Header("Content-Range") String contentRange, @Query("q") String name, @Query("tag") String tag, @Query("start") int start, @Query("count") int count); }
2. 网络请求日志
调试网络请求的时候经常需要关注一下请求参数和返回值,以便判断和定位问题出在哪里,Retrofit官方提供了一个很方便查看日志的Interceptor,你可以控制你需要的打印信息类型,使用方法也很简单。
首先需要在build.gradle文件中引入logging-interceptor
compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
同上文提到的CustomInterceptor和RequestInterceptor一样,添加到OkHttpClient创建处即可,完整的示例代码如下:
private static OkHttpClient getNewClient(){ HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); logging.setLevel(HttpLoggingInterceptor.Level.BODY); return new OkHttpClient.Builder() .addInterceptor(new CustomInterceptor()) .addInterceptor(logging) .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) .build(); }
HttpLoggingInterceptor提供了4中控制打印信息类型的等级,分别是NONE,BASIC,HEADERS,BODY,接下来分别来说一下相应的打印信息类型。
-
NONE
没有任何日志信息
-
Basic
打印请求类型,URL,请求体大小,返回值状态以及返回值的大小
D/HttpLoggingInterceptor$Logger: --> POST /upload HTTP/1.1 (277-byte body) D/HttpLoggingInterceptor$Logger: <-- HTTP/1.1 200 OK (543ms, -1-byte body)
-
Headers
打印返回请求和返回值的头部信息,请求类型,URL以及返回值状态码
<-- 200 OK https://api.douban.com/v2/book/search?q=%E5%B0%8F%E7%8E%8B%E5%AD%90&start=0&count=3&token=tokenValue (3787ms) D/OkHttp: Date: Sat, 06 Aug 2016 14:26:03 GMT D/OkHttp: Content-Type: application/json; charset=utf-8 D/OkHttp: Transfer-Encoding: chunked D/OkHttp: Connection: keep-alive D/OkHttp: Keep-Alive: timeout=30 D/OkHttp: Vary: Accept-Encoding D/OkHttp: Expires: Sun, 1 Jan 2006 01:00:00 GMT D/OkHttp: Pragma: no-cache D/OkHttp: Cache-Control: must-revalidate, no-cache, private D/OkHttp: Set-Cookie: bid=D6UtQR5N9I4; Expires=Sun, 06-Aug-17 14:26:03 GMT; Domain=.douban.com; Path=/ D/OkHttp: X-DOUBAN-NEWBID: D6UtQR5N9I4 D/OkHttp: X-DAE-Node: dis17 D/OkHttp: X-DAE-App: book D/OkHttp: Server: dae D/OkHttp: <-- END HTTP
-
Body
打印请求和返回值的头部和body信息
<-- 200 OK https://api.douban.com/v2/book/search?q=%E5%B0%8F%E7%8E%8B%E5%AD%90&tag=&start=0&count=3&token=tokenValue (3583ms) D/OkHttp: Connection: keep-alive D/OkHttp: Date: Sat, 06 Aug 2016 14:29:11 GMT D/OkHttp: Keep-Alive: timeout=30 D/OkHttp: Content-Type: application/json; charset=utf-8 D/OkHttp: Vary: Accept-Encoding D/OkHttp: Expires: Sun, 1 Jan 2006 01:00:00 GMT D/OkHttp: Transfer-Encoding: chunked D/OkHttp: Pragma: no-cache D/OkHttp: Connection: keep-alive D/OkHttp: Cache-Control: must-revalidate, no-cache, private D/OkHttp: Keep-Alive: timeout=30 D/OkHttp: Set-Cookie: bid=ESnahto1_Os; Expires=Sun, 06-Aug-17 14:29:11 GMT; Domain=.douban.com; Path=/ D/OkHttp: Vary: Accept-Encoding D/OkHttp: X-DOUBAN-NEWBID: ESnahto1_Os D/OkHttp: Expires: Sun, 1 Jan 2006 01:00:00 GMT D/OkHttp: X-DAE-Node: dis5 D/OkHttp: Pragma: no-cache D/OkHttp: X-DAE-App: book D/OkHttp: Cache-Control: must-revalidate, no-cache, private D/OkHttp: Server: dae D/OkHttp: Set-Cookie: bid=5qefVyUZ3KU; Expires=Sun, 06-Aug-17 14:29:11 GMT; Domain=.douban.com; Path=/ D/OkHttp: X-DOUBAN-NEWBID: 5qefVyUZ3KU D/OkHttp: X-DAE-Node: dis17 D/OkHttp: X-DAE-App: book D/OkHttp: Server: dae D/OkHttp: {"count":3,"start":0,"total":778,"books":[{"rating":{"max":10,"numRaters":202900,"average":"9.0","min":0},"subtitle":"","author":["[法] 圣埃克苏佩里"],"pubdate":"2003-8","tags":[{"count":49322,"name":"小王子","title":"小王子"},{"count":41381,"name":"童话","title":"童话"},{"count":19773,"name":"圣埃克苏佩里","title":"圣埃克苏佩里"} D/OkHttp: <-- END HTTP (13758-byte body)
3. 为某个请求设置完整的URL
假如说你的某一个请求不是以base_url开头该怎么办呢?别着急,办法很简单,看下面这个例子你就懂了
public interface BlueService { @GET public Call<ResponseBody> profilePicture(@Url String url); } Retrofit retrofit = Retrofit.Builder() .baseUrl("https://your.api.url/"); .build(); BlueService service = retrofit.create(BlueService.class); service.profilePicture("https://s3.amazon.com/profile-picture/path");
直接用@Url注解的方式传递完整的url地址即可。
4. 取消请求
Call提供了cancel方法可以取消请求,前提是该请求还没有执行
String fileUrl = "http://futurestud.io/test.mp4"; Call<ResponseBody> call = downloadService.downloadFileWithDynamicUrlSync(fileUrl); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { Log.d(TAG, "request success"); } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { if (call.isCanceled()) { Log.e(TAG, "request was cancelled"); } else { Log.e(TAG, "other larger issue, i.e. no network connection?"); } } }); } // 触发某个动作,例如用户点击了取消请求的按钮 call.cancel(); }
四、结语
关于Retrofit常用的方法基本上已经介绍完了,有些请求由于工作保密性的原因,所以就没有放出来,但是基本的方法和操作都是有的,仿照文中提到的代码就可以实现你想要的功能。参考了国外的一则系列教程和liangfei的一篇文章图解 Retrofit - ServiceMethod,由于本人能力有限,有错误或者表述不准确的地方还望多多留言指正。
欢迎 Follow 我的 GitHub 账户: https://github.com/duanyytop
-
-
retrofit封装
2017-09-17 16:36:42retrofit封装retrofit封装retrofit封装retrofit封装retrofit封装retrofit封装retrofit封装retrofit封装retrofit封装 -
Retrofit基本使用
2021-01-03 19:52:36文章目录Retrofit基本使用简介Retrofit注解方法注解标记注解请求头注解参数注解简单使用引入Retrofit依赖及添加权限创建Retrofit实例初步封装定义API接口创建代理对象接口调用 – 简介 Retrofit文档 Retrofit Github... -
Retrofit2详解
2018-11-19 10:21:06Retrofit框架: 它是Square公司开发的现在非常流行的网络框架 retrofit2.0它依赖于OkHttp,在这里我们也不需要显示的导入okHttp,在retrofit中已经导入okhttp3 性能好,处理快,使用简单,Retrofit 是安卓上最... -
Retrofit使用简介
2016-08-19 10:38:29Retrofit -
Retrofit实现原理
2020-09-04 17:21:52Retrofit的使用是动态代理,方法注解,建造者和适配器等成熟的技术。解决api的耦合 一。动态代理 retrofit会生成一个接口实例。 //用retrofit加工出对应的接口实例对象 INetApiService netApiService= retrofit.... -
Retrofit 2.0
2019-03-11 16:34:201.简介 ...1:添加Retrofit库的依赖 1. 在Gradle加入Retrofit库的依赖 build.gradle dependencies { compile 'com.squareup.retrofit2:retrofit:2.0.2' // Retrofit库 compile 'com.squar... -
Retrofit学习
2019-04-30 12:58:30Retrofit 官网:https://square.github.io/retrofit/ github:https://github.com/square/retrofit -
Retrofit源码学习一:Retrofit介绍
2019-07-01 14:45:33Retrofit源码学习一:Retrofit介绍 Retrofit源码学习二:代理模式 Retrofit源码学习三:Retrofit源码详解一 Retrofit源码学习四:Retrofit源码详解二 Retrofit源码学习五:Retrofit中同步、异步请求解析 ... -
Retrofit使用
2019-06-14 06:41:21Retrofit是什么? Retrofit就是一个Http请求库,和其它Http库最大区别在于通过大范围使用注解简化Http请求。目前Retrofit 2.0底层是依赖OkHttp实现的,也就是说Retrofit本质上就是对OkHttp的更进一步封装。那么我们... -
Retrofit封装
2019-03-17 15:52:37package com.bwei.shopping.utils; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; public class RetrofitUtils { //单利 private static RetrofitUtils retrofitUtils... -
Retrofit缓存
2019-04-11 17:22:19相关文章: 在 Retrofit 和 OkHttp 中使用网络缓存,提高访问效率 Retrofit2+okhttp3缓存设置 -
Retrofit详解
2018-03-08 17:23:54Retrofit2.0的使用教程 Retrofit2.0源码分析指南 -
Retrofit入门
2018-09-25 20:24:30想我一年之前每天都在使用Retrofit,一年之后每天都在使用落后的Volley。 因为平时开发中经常发现demo需要进行网络请求,现场编写一个网络请求的库有点手忙脚乱,所以的话干脆写一篇博客记录下来,以后demo再需要...
-
Postman-linux-x64-7.14.0.tar.gz
-
Docker学习(二)HelloWorld及运行原理简介
-
[错误解决]centos中使用kubeadm方式搭建多master的高可用K8S集群
-
python办公自动化技巧
-
Unity Playing模式下鼠标点击放置预制体
-
FPGA基于dds的正弦波发生器与频率计综合设计作业
-
linux epoll多线程编程 例子
-
处理小程序TLS 版本必须大于等于 1.2
-
flutter插件调用APP页面、使用原生aar,framework库
-
stm32zet6_pwm输出_外部脉冲计数pwm脉冲个数
-
杨辉三角
-
国家注册渗透测试工程师(Web安全)
-
三维地图GIS大数据可视化
-
Redis数据库入门与使用
-
stm8l152-6开发板全套资料-C文档类资源
-
使用stylus
-
2021最新Kubernetes(k8s)集群实战精讲
-
阿里云云计算ACP考试必备教程
-
AC6904D4规格书V1.0.pdf
-
Django-ORM框架