Retrofit2.0使用总结及注意事项
2016-12-20 14:02
561 查看
概述
随着Google对HttpClient 摒弃,和Volley的逐渐没落,OkHttp开始异军突起,而Retrofit则对okHttp进行了强制依赖。Retrofit是由Square公司出品的针对于Android和Java的类型安全的Http客户端,
如果看源码会发现其实质上就是对okHttp的封装,使用面向接口的方式进行网络请求,利用动态生成的代理类封装了网络接口请求的底层,
其将请求返回javaBean,对网络认证 REST API进行了很好对支持此,使用Retrofit将会极大的提高我们应用的网络体验。
REST
既然是RESTful架构,那么我们就来看一下什么是REST吧。 REST(REpresentational State Transfer)是一组架构约束条件和原则。
RESTful架构都满足以下规则:
(1)每一个URI代表一种资源;
(2)客户端和服务器之间,传递这种资源的某种表现层;
(3)客户端通过四个HTTP动词,对服务器端资源进行操作,实现”表现层状态转化”。
更多关于REST的介绍:什么是REST - GitHub讲解的非常详细
2.0与1.9使用比较
如果之前使用过Retrofit1,会发现2.0后的API会有一些变化, 比如创建方式,拦截器,错误处理,转换器等,如下我们列举以下他们使用起来具体的区别有哪些。
(1) 在Retrofit1中使用的是RestAdapter,而Retrofit2中使用的Retrofit实例,之前的setEndpoint变为了baseUrl。
(2) Retrofit1中使用setRequestInterceptor设置拦截器,对http请求进行相应等处理。
(3) Retrofit2通过OKHttp的拦截器拦截http请求进行监控,重写或重试等,包括日志打印等。
(4) converter,Retrofit1中的setConverter,换以addConverterFactory,用于支持Gson转换。
Retrofit1体验不好的地方:
(1) Retrofit1不能同时操作response返回数据
(比如说返回的 Header 部分或者 URL)和序列化后的数据
(JAVABEAN),
(2) Retrofit1中同步和异步执行同一个方法需要分别定义接口。
(3) Retrofit1对正在进行的网络任务无法取消。
参考:官方CHANGELOG.md
更新到Retrofit2的一些技巧
1.9使用配置:
//gson converter final static Gson gson = new GsonBuilder() .setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") .serializeNulls() .create(); // client OkHttpClient client = new OkHttpClient(); client.setReadTimeout(12, TimeUnit.SECONDS); RestAdapter.Builder builder = new RestAdapter.Builder(); builder.setClient(new OkClient(client)) //日志打印 .setLogLevel(RestAdapter.LogLevel.FULL) //baseUrl .setEndpoint("https://api.github.com") //转换器 .setConverter(new GsonConverter(gson)) //错误处理 .setErrorHandler(new ErrorHandler() { @Override public Throwable handleError(RetrofitError cause) { return null; } }) //拦截器 .setRequestInterceptor(authorizationInterceptor) RestAdapter restAdapter = builder.build(); apiService = restAdapter.create(ApiService.class);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2.0使用配置
引入依赖compile 'com.squareup.retrofit2:retrofit:2.0.2' compile 'com.squareup.retrofit2:converter-gson:2.0.2' compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2' compile 'com.squareup.okhttp3:logging-interceptor:3.2.0'1
2
3
4
5
1
2
3
4
5
OkHttp配置
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); client = new OkHttpClient.Builder() .addInterceptor(interceptor) .retryOnConnectionFailure(true) .connectTimeout(15, TimeUnit.SECONDS) .addNetworkInterceptor(authorizationInterceptor) .build();1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
其中 level 为 BASIC / HEADERS / BODY,BODY等同于1.9中的FULL
retryOnConnectionFailure:错误重联
addInterceptor:设置应用拦截器,可用于设置公共参数,头信息,日志拦截等
addNetworkInterceptor:网络拦截器,可以用于重试或重写,对应与1.9中的setRequestInterceptor。
参考:Interceptors
中文翻译:Okhttp-wiki 之 Interceptors 拦截器
Retrofit配置
Retrofit retrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .client(client) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create(gson)) .build(); apiService = retrofit.create(ApiService.class);1
2
3
4
5
6
7
1
2
3
4
5
6
7
其中baseUrl相当于1.9中的setEndPoint,
addCallAdapterFactory提供RxJava支持,如果没有提供响应的支持(RxJava,Call),则会跑出异常。
addConverterFactory提供Gson支持,可以添加多种序列化Factory,但是GsonConverterFactory必须放在最后,否则会抛出异常。
参考:用 Retrofit 2 简化 HTTP 请求
2.0使用介绍
注意:retrofit2.0后:BaseUrl要以/结尾;@GET 等请求不要以/开头;@Url: 可以定义完整url,不要以 / 开头。 关于URL拼接注意事项:Retrofit 2.0:有史以来最大的改进
基本用法:
//定以接口 public interface GitHubService { @GET("users/{user}/repos") Call<List<Repo>> listRepos(@Path("user") String user); } //获取实例 Retrofit retrofit = new Retrofit.Builder() //设置OKHttpClient,如果不设置会提供一个默认的 .client(new OkHttpClient()) //设置baseUrl .baseUrl("https://api.github.com/") //添加Gson转换器 .addConverterFactory(GsonConverterFactory.create()) .build(); GitHubService service = retrofit.create(GitHubService.class); //同步请求 //https://api.github.com/users/octocat/repos Call<List<Repo>> call = service.listRepos("octocat"); try { Response<List<Repo>> repos = call.execute(); } catch (IOException e) { e.printStackTrace(); } //call只能调用一次。否则会抛 IllegalStateException Call<List<Repo>> clone = call.clone(); //异步请求 clone.enqueue(new Callback<List<Repo>>() { @Override public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) { // Get result bean from response.body() List<Repo> repos = response.body(); // Get header item from response String links = response.headers().get("Link"); /** * 不同于retrofit1 可以同时操作序列化数据javabean和header */ } @Override public void onFailure(Call<List<Repo>> call, Throwable t) { } }); // 取消 call.cancel();1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
//rxjava support public interface GitHubService { @GET("users/{user}/repos") Observable<List<Repo>> listRepos(@Path("user") String user); } // 获取实例 // Http request Observable<List<Repo>> call = service.listRepos("octocat");1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
retrofit注解:
方法注解,包含@GET、@POST、@PUT、@DELETE、@PATH、@HEAD、@OPTIONS、@HTTP。 标记注解,包含@FormUrlEncoded、@Multipart、@Streaming。
参数注解,包含@Query,@QueryMap、@Body、@Field,@FieldMap、@Part,@PartMap。
其他注解,@Path、@Header,@Headers、@Url
几个特殊的注解
@HTTP:可以替代其他方法的任意一种
/** * method 表示请的方法,不区分大小写 * path表示路径 * hasBody表示是否有请求体 */ @HTTP(method = "get", path = "users/{user}", hasBody = false) Call<ResponseBody> getFirstBlog(@Path("user") String user);1
2
3
4
5
6
7
1
2
3
4
5
6
7
@Url:使用全路径复写baseUrl,适用于非统一baseUrl的场景。
@GET Call<ResponseBody> v3(@Url String url);1
2
1
2
@Streaming:用于下载大文件
@Streaming @GET Call<ResponseBody> downloadFileWithDynamicUrlAsync(@Url String fileUrl);1
2
3
1
2
3
ResponseBody body = response.body(); long fileSize = body.contentLength(); InputStream inputStream = body.byteStream();1
2
3
1
2
3
常用注解
@Path:URL占位符,用于替换和动态更新,相应的参数必须使用相同的字符串被@Path进行注释
@GET("group/{id}/users") Call<List<User>> groupList(@Path("id") int groupId); //--> http://baseurl/group/groupId/users //等同于: @GET Call<List<User>> groupListUrl( @Url String url);1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
@Query,@QueryMap:查询参数,用于GET查询,需要注意的是@QueryMap可以约定是否需要encode
@GET("group/users") Call<List<User>> groupList(@Query("id") int groupId); //--> http://baseurl/group/users?id=groupId[/code]1 2
3
1
2
3Call<List<News>> getNews((@QueryMap(encoded=true) Map<String, String> options);1
1
@Body:用于POST请求体,将实例对象根据转换方式转换为对应的json字符串参数,
这个转化方式是GsonConverterFactory定义的。@POST("add") Call<List<User>> addUser(@Body User user);1
2
1
2
@Field,@FieldMap:Post方式传递简单的键值对,
需要添加@FormUrlEncoded表示表单提交
Content-Type:application/x-www-form-urlencoded@FormUrlEncoded @POST("user/edit") Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);1
2
3
1
2
3
@Part,@PartMap:用于POST文件上传
其中@Part MultipartBody.Part代表文件,@Part(“key”) RequestBody代表参数
需要添加@Multipart表示支持文件上传的表单,Content-Type: multipart/form-data@Multipart @POST("upload") Call<ResponseBody> upload(@Part("description") RequestBody description, @Part MultipartBody.Part file);1
2
3
4
1
2
3
4// https://github.com/iPaulPro/aFileChooser/blob/master/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java // use the FileUtils to get the actual file by uri File file = FileUtils.getFile(this, fileUri); // create RequestBody instance from file RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file); // MultipartBody.Part is used to send also the actual file name MultipartBody.Part body = MultipartBody.Part.createFormData("picture", file.getName(), requestFile); // add another part within the multipart request String descriptionString = "hello, this is description speaking"; RequestBody description = RequestBody.create( MediaType.parse("multipart/form-data"), descriptionString);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
参考: Retrofit2 完全解析 探索与okhttp之间的关系
Retrofit 2 — How to Upload Files to Server
@Header:header处理,不能被互相覆盖,用于修饰参数,//动态设置Header值 @GET("user") Call<User> getUser(@Header("Authorization") String authorization)1
2
3
1
2
3
等同于 ://静态设置Header值 @Headers("Authorization: authorization")//这里authorization就是上面方法里传进来变量的值 @GET("widget/list") Call<User> getUser()1
2
3
4
1
2
3
4
@Headers 用于修饰方法,用于设置多个Header值:@Headers({ "Accept: application/vnd.github.v3.full+json", "User-Agent: Retrofit-Sample-App" }) @GET("users/{username}") Call<User> getUser(@Path("username") String username);1
2
3
4
5
6
1
2
3
4
5
6retrofit默认情况下支持的converts有Gson,Jackson,Moshi…
自定义Converter
要自定义Converter<F, T>,需要先看一下GsonConverterFactory的实现,
GsonConverterFactory实现了内部类Converter.Factory。
其中GsonConverterFactory中的主要两个方法,主要用于解析request和response的,
在Factory中还有一个方法stringConverter,用于String的转换。//主要用于响应体的处理,Factory中默认实现为返回null,表示不处理 @Override public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type)); return new GsonResponseBodyConverter<>(gson, adapter); } /** *主要用于请求体的处理,Factory中默认实现为返回null,不能处理返回null *作用对象Part、PartMap、Body */ @Override public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) { TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type)); return new GsonRequestBodyConverter<>(gson, adapter); }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18//Converter.Factory$stringConverter /** *作用对象Field、FieldMap、Header、Path、Query、QueryMap *默认处理是toString */ public Converter<?, String> stringConverter(Type type, Annotation[] annotations, Retrofit retrofit) { return null; }1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
GsonRequestBodyConverter实现了Converter<F, T>接口,
主要实现了转化的方法T convert(F value) throws IOException;1
1
StringConverterFactory实现源码Retrofit 2.0 底层依赖于okHttp,所以需要使用okHttp的Interceptors 来对所有请求进行拦截。
自定义Interceptor
我们可以通过自定义Interceptor来实现很多操作,打印日志,缓存,重试等等。
要实现自己的拦截器需要有以下步骤
(1) 需要实现Interceptor接口,并复写intercept(Chain chain)方法,返回response
(2) Request 和 Response的Builder中有header,addHeader,headers方法,需要注意的是使用header有重复的将会被覆盖,而addHeader则不会。
标准的 Interceptor写法public class OAuthInterceptor implements Interceptor { private final String username; private final String password; public OAuthInterceptor(String username, String password) { this.username = username; this.password = password; } @Override public Response intercept(Chain chain) throws IOException { String credentials = username + ":" + password; String basic = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP); Request originalRequest = chain.request(); String cacheControl = originalRequest.cacheControl().toString(); Request.Builder requestBuilder = originalRequest.newBuilder() //Basic Authentication,也可用于token验证,OAuth验证 .header("Authorization", basic) .header("Accept", "application/json") .method(originalRequest.method(), originalRequest.body()); Request request = requestBuilder.build(); Response originalResponse = chain.proceed(request); Response.Builder responseBuilder = //Cache control设置缓存 originalResponse.newBuilder().header("Cache-Control", cacheControl); return responseBuilder.build(); } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35设置缓存就需要用到OkHttp的interceptors,缓存的设置需要靠请求和响应头。
缓存策略
如果想要弄清楚缓存机制,则需要了解一下HTTP语义,其中控制缓存的就是Cache-Control字段
参考:Retrofit2.0+okhttp3缓存机制以及遇到的问题
How Retrofit with OKHttp use cache data when offline
使用Retrofit和Okhttp实现网络缓存。无网读缓存,有网根据过期时间重新请求
一般情况下我们需要达到的缓存效果是这样的:
没有网或者网络较差的时候要使用缓存(统一设置)
有网络的时候,要保证不同的需求,实时性数据不用缓存,一般请求需要缓存(单个请求的header来实现)。
OkHttp3中有一个Cache类是用来定义缓存的,此类详细介绍了几种缓存策略,具体可看此类源码。
noCache :不使用缓存,全部走网络
noStore : 不使用缓存,也不存储缓存
onlyIfCached : 只使用缓存
maxAge :设置最大失效时间,失效则不使用
maxStale :设置最大失效时间,失效则不使用
minFresh :设置最小有效时间,失效则不使用
FORCE_NETWORK : 强制走网络
FORCE_CACHE :强制走缓存这个是缓存文件的存放位置,okhttp默认是没有缓存,且没有缓存目录的。
配置目录private static final int HTTP_RESPONSE_DISK_CACHE_MAX_SIZE = 10 * 1024 * 1024; private Cache cache() { //设置缓存路径 final File baseDir = AppUtil.getAvailableCacheDir(sContext); final File cacheDir = new File(baseDir, "HttpResponseCache"); //设置缓存 10M return new Cache(cacheDir, HTTP_RESPONSE_DISK_CACHE_MAX_SIZE); }1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
其中获取cacahe目录,我们一般采取的策略就是应用卸载,即删除。一般就使用如下两个目录:
data/$packageName/cache:Context.getCacheDir()
/storage/sdcard0/Andorid/data/$packageName/cache:Context.getExternalCacheDir()
且当sd卡空间小于data可用空间时,使用data目录。
最后来一张图看懂Android内存结构,参考:Android文件存储使用参考 - liaohuqiu/** * | ($rootDir) * +- /data -> Environment.getDataDirectory() * | | * | | ($appDataDir) * | +- data/$packageName * | | * | | ($filesDir) * | +- files -> Context.getFilesDir() / Context.getFileStreamPath("") * | | | * | | +- file1 -> Context.getFileStreamPath("file1") * | | * | | ($cacheDir) * | +- cache -> Context.getCacheDir() * | | * | +- app_$name ->(Context.getDir(String name, int mode) * | * | ($rootDir) * +- /storage/sdcard0 -> Environment.getExternalStorageDirectory()/ Environment.getExternalStoragePublicDirectory("") * | | * | +- dir1 -> Environment.getExternalStoragePublicDirectory("dir1") * | | * | | ($appDataDir) * | +- Andorid/data/$packageName * | | * | | ($filesDir) * | +- files -> Context.getExternalFilesDir("") * | | | * | | +- file1 -> Context.getExternalFilesDir("file1") * | | +- Music -> Context.getExternalFilesDir(Environment.Music); * | | +- Picture -> Context.getExternalFilesDir(Environment.Picture); * | | +- ... -> Context.getExternalFilesDir(String type) * | | * | | ($cacheDir) * | +- cache -> Context.getExternalCacheDir() * | | * | +- ??? * <p/> * <p/> * 1. 其中$appDataDir中的数据,在app卸载之后,会被系统删除。 * <p/> * 2. $appDataDir下的$cacheDir: * Context.getCacheDir():机身内存不足时,文件会被删除 * Context.getExternalCacheDir():空间不足时,文件不会实时被删除,可能返回空对象,Context.getExternalFilesDir("")亦同 * <p/> * 3. 内部存储中的$appDataDir是安全的,只有本应用可访问 * 外部存储中的$appDataDir其他应用也可访问,但是$filesDir中的媒体文件,不会被当做媒体扫描出来,加到媒体库中。 * <p/> * 4. 在内部存储中:通过 Context.getDir(String name, int mode) 可获取和 $filesDir / $cacheDir 同级的目录 * 命名规则:app_ + name,通过Mode控制目录是私有还是共享 * <p/> * <code> * Context.getDir("dir1", MODE_PRIVATE): * Context.getDir: /data/data/$packageName/app_dir1 * </code> */1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56配置单个请求的@Headers,设置此请求的缓存策略,不影响其他请求的缓存策略,不设置则没有缓存。
缓存第一种类型// 设置 单个请求的 缓存时间 @Headers("Cache-Control: max-age=640000") @GET("widget/list") Call<List<Widget>> widgetList();1
2
3
4
1
2
3
4有网和没网都先读缓存,统一缓存策略,降低服务器压力。
缓存第二种类型private Interceptor cacheInterceptor() { Interceptor cacheInterceptor = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); Response response = chain.proceed(request); String cacheControl = request.cacheControl().toString(); if (TextUtils.isEmpty(cacheControl)) { cacheControl = "public, max-age=60"; } return response.newBuilder() .header("Cache-Control", cacheControl) .removeHeader("Pragma") .build(); } }; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
此中方式的缓存Interceptor实现:ForceCachedInterceptor.java结合前两种,离线读取本地缓存,在线获取最新数据(读取单个请求的请求头,亦可统一设置)。
缓存第三种类型private Interceptor cacheInterceptor() { return new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); if (!AppUtil.isNetworkReachable(sContext)) { request = request.newBuilder() //强制使用缓存 .cacheControl(CacheControl.FORCE_CACHE) .build(); } Response response = chain.proceed(request); if (AppUtil.isNetworkReachable(sContext)) { //有网的时候读接口上的@Headers里的配置,你可以在这里进行统一的设置 String cacheControl = request.cacheControl().toString(); Logger.i("has network ,cacheControl=" + cacheControl); return response.newBuilder() .header("Cache-Control", cacheControl) .removeHeader("Pragma") .build(); } else { int maxStale = 60 * 60 * 24 * 28; // tolerate 4-weeks stale Logger.i("network error ,maxStale="+maxStale); return response.newBuilder() .header("Cache-Control", "public, only-if-cached, max-stale="+maxStale) .removeHeader("Pragma") .build(); } } }; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
此中方式的缓存Interceptor实现:OfflineCacheControlInterceptor.java在请求网络的时候,我们不止会得到HttpException,还有我们和服务器约定的errorCode和errorMessage,为了统一处理,我们可以
错误处理
预处理以下上面两个字段,定义BaseModel,在ConverterFactory中进行处理,
可参照:
Retrofit+RxJava实战日志(3)-网络异常处理
retrofit-2-simple-error-handling一般在没有网络的时候使用缓存数据,有网络的时候及时重试获取最新数据,其中获取是否有网络,我们采用广播的形式:
网络状态监听public class NetWorkReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { HttpNetUtil.INSTANCE.setConnected(context); } }1
2
3
4
5
6
7
1
2
3
4
5
6
7
HttpNetUtil实时获取网络连接状态,关键代码/** * 获取是否连接 */ public boolean isConnected() { return isConnected; } /** * 判断网络连接是否存在 * * @param context */ public void setConnected(Context context) { ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); if (manager == null) { setConnected(false); if (networkreceivers != null) { for (int i = 0, z = networkreceivers.size(); i < z; i++) { Networkreceiver listener = networkreceivers.get(i); if (listener != null) { listener.onConnected(false); } } } } NetworkInfo info = manager.getActiveNetworkInfo(); boolean connected = info != null && info.isConnected(); setConnected(connected); if (networkreceivers != null) { for (int i = 0, z = networkreceivers.size(); i < z; i++) { Networkreceiver listener = networkreceivers.get(i); if (listener != null) { listener.onConnected(connected); } } } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
在需要监听网络的界面或者base(需要判断当前activity是否在栈顶)实现Networkreceiver。全局单利的OkHttpClient:
Retrofit封装okHttp() { HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); okHttpClient = new OkHttpClient.Builder() //打印日志 .addInterceptor(interceptor) //设置Cache目录 .cache(CacheUtil.getCache(UIUtil.getContext())) //设置缓存 .addInterceptor(cacheInterceptor) .addNetworkInterceptor(cacheInterceptor) //失败重连 .retryOnConnectionFailure(true) //time out .readTimeout(TIMEOUT_READ, TimeUnit.SECONDS) .connectTimeout(TIMEOUT_CONNECTION, TimeUnit.SECONDS) .build() ; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
全局单利的Retrofit.Builder,这里返回builder是为了方便我们设置baseUrl的,我们可以动态创建多个api接口,当然也可以用@Url注解Retrofit2Client() { retrofitBuilder = new Retrofit.Builder() //设置OKHttpClient .client(okHttp.INSTANCE.getOkHttpClient()) //Rx .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) //String转换器 .addConverterFactory(StringConverterFactory.create()) //gson转化器 .addConverterFactory(GsonConverterFactory.create()) ; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Retrofit2+RxJava 使用Demo:Retrofit2Demo
参考:
Articles tagged in: Retrofit
官方文档
Retrofit2 完全解析 探索与okhttp之间的关系
Retrofit 2.0 + OkHttp 3.0 配置
更新到Retrofit2的一些技巧
Effective OkHttp
Okhttp-wiki 之 Interceptors 拦截器
Retrofit2.0+okhttp3缓存机制以及遇到的问题
How Retrofit with OKHttp use cache data when offline
使用Retrofit和Okhttp实现网络缓存。无网读缓存,有网根据过期时间重新请求
用 Retrofit 2 简化 HTTP 请求
Retrofit请求参数注解字段说明
Android文件存储使用参考 - liaohuqiu
Retrofit+RxJava实战日志(3)-网络异常处理
retrofit-2-simple-error-handling
相关文章推荐
- Retrofit2.0使用总结及注意事项
- Retrofit2.0使用总结及注意事项
- Retrofit2.0使用总结及注意事项
- Retrofit2.0使用总结及注意事项
- ODP.NET 2.0使用注意事项以及与1.0的区别
- C++ 函数使用总结/编程注意事项
- PDO防注入原理分析以及使用PDO的注意事项总结
- webview使用总结及注意事项
- struts使用总结一:慎用actionServlet成员变量,actionServlet生命周期,actionForm生命周期,struts上传注意事项
- MySQL索引类型总结和使用技巧以及注意事项
- 使用OpenSSL工具制作X.509证书的方法及其注意事项总结
- 【总结】C#中的Regex的使用心得和注意事项
- 自己总结的Android studio 使用快捷键及注意事项(未完成版)
- 使用Myeclipse9配置struts1.2+spring2.0+hibernate3.2注意事项
- Mybatis的使用注意事项和出错的一些总结
- .NET 2.0 SQL依赖注意事项(转载:原文《使用SQL Server 2005 Query Notification的几个注意事项》)
- 总结下linux下的IPC使用原理及注意事项
- JSP中使用cookie的方法以及注意事项总结
- java中使用switch-case的用法及注意事项超全总结
- 黑马程序员-OC语言-self修饰变量以及使用总结和注意事项(听课笔记)