准备学习下retrofit框架的使用,然后封装下,现在不懂retrofit都不意思说自己是android开发,所以也学习下,在github上的地址是:https://github.com/square/retrofit
要使用retrofit要引入的库还是挺多的
//rxjava引入的包 compile 'io.reactivex.rxjava2:rxandroid:2.0.1' compile 'io.reactivex.rxjava2:rxjava:2.1.7' //retrofit引入的包 compile 'com.squareup.retrofit2:retrofit:2.3.0' compile 'com.google.code.gson:gson:2.2.4' //返回给我的是一个json解析后的bean compile 'com.squareup.retrofit2:converter-gson:2.1.0' //rxjava2+retrofit搭配使用的依赖 compile 'com.squareup.retrofit2:adapter-rxjava:2.3.0' //okhttp日记拦截器 compile 'com.squareup.okhttp3:logging-interceptor:3.9.1'在这多说一句,像前面三个引入的在rxandroid,retrofit的 github文档上就可以直接copy过来,但是像后面三个我怎么在studio下依赖就是找不到,后面实在没办法,就直接百度了下到他的官网介绍中去找对应的版本了,
算是一个小插曲吧.
开发包引入了以后就是学习怎么使用了,首先看下他的文档,肯定是有demo给我们介绍的.
http://square.github.io/retrofit/
上面是他的官网文档,首先看下它给的例子,然后照着他写的抄就行
第一步:
public interface GitHubService { @GET("users/{user}/repos") Call<List<Repo>> listRepos(@Path("user") String user); }它定义了一个接口,然后有个方法listRepos,返回的是一个Call对应,还是画图说下容易解释
把上面的图翻译下就是这个:
public interface KSService { @GET("api/data/{Android}/{size}/{page}") Call<Info> getInfoData(@Path("Android") String Android, @Path("size") String size, @Path("page") int page); }第二步:
构建一个Retrofit对象
Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://gank.io/") .addConverterFactory(GsonConverterFactory.create())//支持把请求的json转换bean .build();第三步:
KSService service = retrofit.create(KSService.class);第四步:
Call<Info> call = service.getInfoData("Android","10",1);//传递的参数第五步:
call.enqueue(new Callback<Info>() { @Override public void onResponse(Call<Info> call, Response<Info> response) { Info info = response.body(); List<Info.ResultsBean> list = info.getResults(); Log.e(TAG,"url="+list.get(0).getUrl()); } @Override public void onFailure(Call<Info> call, Throwable t) { } });
上面就是发送一个异步get的请求,同步我不会再讲了,几乎没人用同步去请求网络,可能第一次写感觉乖乖的,但是多写几次就熟练了.
我们知道get方式请求,我们可以直接把参数拼接在url后面,这样就不用带参数,
@GET("api/data/Android/10/1") Call<Info> getInfoData();还有一种就是如果我们要传的参数有很多,这个时候,就可以使用使用这个注解:@QueryMap
@GET("api/data/") Call<Info> getInfoData(@QueryMap Map<String, String> map);在传参的时候传递一个map集合就可以了
Map<String,String> map = new HashMap<>(); map.put("Android","Android"); map.put("size","10"); map.put("page","1"); Call<Info> call = service.getInfoData(map);//传递的参数但有的时候用不了这个,因为这个是把参数拼接在url后面,比如这个url:http://gank.io/api/data/Android/10/1如果使用@QueryMap传递多个参数,最后的请求url是这个:http://gank.io/api/data/?page=1&size=10&Android=Android
还有一个用于在参数的注解@Query
@GET("api/data/") Call<Info> getInfoData(@Query("Android") String Android, @Query("size") String size, @Query("page") int page);记住如果使用@Query注解作用在参数的时候,url后面不要带参数,请看请求的地址:
发现也是把key_value进行拼接的在url后面,所以@Path和@Query注解有啥不同就出现了
@Path是将value值直接放在url后面,用/分割
@Query是将key-value的形式拼接在url后面
@QueryMap是将多个key-value的形式拼接在url后面
当然如果想对参数进行编码的话,他们都提供的有个encode,默认值是为false,如果不对参数进行url编码的话就传true,
@Query还能传递一个数组,相当于是我们Java中的可变参数一样
@GET("api/data/") Call<Info> getInfoData(@Query ("Android")String...Android );也就是说他的key是一样的,只是传递的value不同而已,
http://gank.io/api/data/?Android=Android&Android=java&Android=php
Post请求
现在自己使用tomcat搭建一个简单的服务器,来玩下post请求
@POST("aa/HelloServlet") Call<Person> login(@Field("username")String username, @Field("password") String password);这是用户登录的,传递了二个参数
public void post(View view){ OkHttpClient httpClient = new OkHttpClient(); if (BuildConfig.DEBUG) { HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); logging.setLevel(HttpLoggingInterceptor.Level.BODY); httpClient = new OkHttpClient.Builder().addInterceptor(logging).build(); } Retrofit retrofit = new Retrofit.Builder() .client(httpClient) .baseUrl("http://192.168.1.107:8080/") .addConverterFactory(GsonConverterFactory.create())//支持把请求的json转换bean .build(); KSService service = retrofit.create(KSService.class); Call<Person> call = service.login("zhouguizhi","123456"); call.enqueue(new Callback<Person>() { @Override public void onResponse(Call<Person> call, Response<Person> response) { Log.e(TAG,"登录请求成功"); Log.e(TAG,"response="+response.body()); } @Override public void onFailure(Call<Person> call, Throwable t) { } }); }发现报错了,错误日记:
意思是说我们传递的参数没有进行编码,所以post请求一定要加@FormUrlEncoded
@FormUrlEncoded @POST("aa/HelloServlet") Call<Person> login(@Field("username")String username, @Field("password") String password);再试试就成功了,
服务器接受的消息:
客户端接收到的
如果有多个参数也可以使用@FieldMap
文件下载
首先使用get方法从豆瓣上下载一张图片
@GET("/view/photo/m/public/p2505783407.webp") Call<ResponseBody> download_get();我把下载后的文件存放在sd卡下的:
public void download_get(View view){ OkHttpClient httpClient = new OkHttpClient(); if (BuildConfig.DEBUG) { HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); logging.setLevel(HttpLoggingInterceptor.Level.BODY); httpClient = new OkHttpClient.Builder().addInterceptor(logging).build(); } Retrofit retrofit = new Retrofit.Builder() .client(httpClient) .baseUrl("https://img1.doubanio.com") .build(); KSService service = retrofit.create(KSService.class); Call<ResponseBody> call = service.download_get(); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { InputStream inputStream = response.body().byteStream(); Log.e(TAG,"下载成功="); FileOutputStream fileOutputStream = null; try { fileOutputStream = new FileOutputStream(new File(getPath(),"/zgz2.jpg")); byte[] buffer = new byte[2048]; int len = 0; while ((len = inputStream.read(buffer)) != -1) { fileOutputStream.write(buffer, 0, len); } fileOutputStream.flush(); } catch (IOException e) { Log.e(TAG,"下载过程中失败="+e); }finally { try { if(null!=fileOutputStream){ fileOutputStream.close(); } } catch (IOException e) { e.printStackTrace(); } try { if(inputStream!=null){ inputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { Log.e(TAG,"下载失败="+t.getLocalizedMessage()); } }); }查看日记:
下载成功了我们就到文件管理器中去找下刚才下载的文件
刚才使用get方式文件下载,现在使用post方式文件下载也是一样:
@POST("/view/photo/m/public/p2505783407.webp") Call<ResponseBody> download_post();其他代码不变.文件下载好了,开始学习下文件上传,
文件上传
先来个简单的单文件上传
@Multipart @POST("/aa/UploadServlet") Call<ResponseBody> upload_post(@Part MultipartBody.Part file);实现:
public void upload(View view){ OkHttpClient httpClient = new OkHttpClient(); if (BuildConfig.DEBUG) { HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); logging.setLevel(HttpLoggingInterceptor.Level.BODY); httpClient = new OkHttpClient.Builder().addInterceptor(logging).build(); } Retrofit retrofit = new Retrofit.Builder() .client(httpClient) .baseUrl("http://192.168.1.107:8080/") .build(); File file = new File(getPath(),"zgz3.jpg"); RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file); MultipartBody.Part body = MultipartBody.Part.createFormData("uploadfile", file.getName(), requestBody); KSService service = retrofit.create(KSService.class); Call<ResponseBody> call = service.upload_post(body); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { try { Log.e(TAG,"文件上传成功="+response.body().string()); } catch (IOException e) { e.printStackTrace(); } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { Log.e(TAG,"文件上传失败="+t.getLocalizedMessage()); } }); }log:
在这我弄好久,刚开始是豆瓣上下载的图片上传的
https://img1.doubanio.com/view/photo/albumcover/public/p2220219198.webp
他是webp格式的,我下载后在我电脑上打不开,请求也不成功,后来突然想到了换个jpg格式的,一下子就成功了,折腾了1个多小时,我也是晕死.
下载到我的电脑上的:
服务端代码,也贴下
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Part part=request.getPart("uploadfile");
PrintWriter out=response.getWriter();
System.out.println("ContentType="+part.getContentType()+"\n");
out.print("ContentType="+part.getContentType()+"\n");
System.out.println("size="+part.getSize()+"\n");
out.print("size="+part.getSize()+"\n");
String name = part.getName();
out.print("name="+name+"\n");
part.write("C://Users/zhouguizhijxhz/zgz1.png");
Gson gson=new Gson();
UpLoad upLoad = new UpLoad();
upLoad.setCode(0);
upLoad.setMsg("success");
response.getWriter().write("success");
}
单个文件上传成功了,但是可能要求你上传文件的同时,还要传递参数,这个也搞定下,很快的。
@Multipart @POST("/aa/UploadServlet") Call<ResponseBody> mulitupload(@Part MultipartBody.Part file,@QueryMap Map<String,String> map);
实现
public void upload_params(View view){ OkHttpClient httpClient = new OkHttpClient(); if (BuildConfig.DEBUG) { HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); logging.setLevel(HttpLoggingInterceptor.Level.BODY); httpClient = new OkHttpClient.Builder().addInterceptor(logging).build(); } Retrofit retrofit = new Retrofit.Builder() .client(httpClient) .baseUrl("http://192.168.1.107:8080/") .build(); File file = new File(getPath(),"zgz3.jpg"); RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file); MultipartBody.Part body = MultipartBody.Part.createFormData("uploadfile", file.getName(), requestBody); KSService service = retrofit.create(KSService.class); Map<String,String> map = new HashMap<>(); map.put("name","zhouugizhi"); map.put("time","2017-11-30"); Call<ResponseBody> call = service.mulitupload(body,map); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { try { Log.e(TAG,"文件上传成功="+response.body().string()); } catch (IOException e) { e.printStackTrace(); } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { Log.e(TAG,"文件上传失败="+t.getLocalizedMessage()); } }); }看下服务器接受到传递的参数:
name就是我传递的参数,time没有做打印,现在看下客户度的返回什么数据,我把name,time返回给客户端了
?是中文乱码了,不管,单上文上传并传参也实现了,多文件上传,由于不会服务器端多文件怎么处理,暂时放一放.
retrofit+rxjava
retrofit内置式支持rxjava操作的,当然需要去设置下,请求方法不再是返回一个Call对象了,而是返回一个被观察者Observable,加上下面这行代码:
addCallAdapterFactory(RxJava2CallAdapterFactory.create())
但是发现我怎么发现我没有这个类呢?,原来是我那个rxjava适配器的包没有使用大神的
// compile 'com.squareup.retrofit2:adapter-rxjava:2.3.0' compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0-RC3'使用下面的
使用rxjava方式请求一个get,方法的定义
@GET("api/data/{Android}/{size}/{page}") Observable<ResponseBody> getInfoDataByRxjava(@Path(value = "Android",encoded = true) String Android, @Path(value = "size",encoded = true) String size, @Path(value = "page",encoded = true) int page);实现
public void get_by_rxjava(View view){ OkHttpClient httpClient = new OkHttpClient(); if (BuildConfig.DEBUG) { HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); logging.setLevel(HttpLoggingInterceptor.Level.BODY); httpClient = new OkHttpClient.Builder().addInterceptor(logging).build(); } Retrofit retrofit = new Retrofit.Builder() .client(httpClient) .baseUrl("http://gank.io") .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); KSService service = retrofit.create(KSService.class); Observable<ResponseBody> observable = service.getInfoDataByRxjava("Android","10",1); observable .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer<ResponseBody>(){ @Override public void accept(ResponseBody responseBody) throws Exception { String s = responseBody.string(); Log.e(TAG,"请求的结果:"+s); tv.setText(s); } }); }log:
关于retrofit+rxjava就是这么使用的,只是我们原来单独使用rxjava的是通过操作符create返回一个Observable,现在不用 了在retrofit中,还有就是我们之前是去调异步或者同步的方法去请求网络,使用了额rxjava就不用去掉了,
添加网络日志信息
前面我打印出来的log,如果不做什么处理,是没有这些log的,在retrofit要设置,请求的和返回的log才会打印出来,特别是我们的开发阶段,一定要打log,又可能一个问题,看log就直接解决了,比如后面返回的json数据一个类型出错了,就会导致你转bean抛错误了,在此一定别忘记了添加依赖
compile 'com.squareup.okhttp3:logging-interceptor:3.9.1
关于拦截器都是在OkhttpClient中去设置的,
OkHttpClient httpClient = new OkHttpClient(); if (BuildConfig.DEBUG) { HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); logging.setLevel(HttpLoggingInterceptor.Level.BODY); httpClient = new OkHttpClient.Builder().addInterceptor(logging).build(); }它有四个等级,看下源码就知道了.
public enum Level { /** No logs. */ NONE, /** * Logs request and response lines. * * <p>Example: * <pre>{@code * --> POST /greeting http/1.1 (3-byte body) * * <-- 200 OK (22ms, 6-byte body) * }</pre> */ BASIC, /** * Logs request and response lines and their respective headers. * * <p>Example: * <pre>{@code * --> POST /greeting http/1.1 * Host: example.com * Content-Type: plain/text * Content-Length: 3 * --> END POST * * <-- 200 OK (22ms) * Content-Type: plain/text * Content-Length: 6 * <-- END HTTP * }</pre> */ HEADERS, /** * Logs request and response lines and their respective headers and bodies (if present). * * <p>Example: * <pre>{@code * --> POST /greeting http/1.1 * Host: example.com * Content-Type: plain/text * Content-Length: 3 * * Hi? * --> END POST * * <-- 200 OK (22ms) * Content-Type: plain/text * Content-Length: 6 * * Hello! * <-- END HTTP * }</pre> */ BODY }然后设置给retrofit
Retrofit retrofit = new Retrofit.Builder() .client(httpClient) .baseUrl("http://gank.io") .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build();第2行就是了.
body级别的log包含请求头,响应头,以及请求数据都会打印出来。
URL统一追加参数
public class AppendUrlParamInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request();//拿到发送的请求 HttpUrl httpUrl = request.url().newBuilder().addQueryParameter("version","1.0") .addQueryParameter("channel","360") .addQueryParameter("versionCode","10") .addQueryParameter("deviceId","abasersgdhdjjfs5688") .build(); //重要一步 使用新的url构建一个Request发送给后台 Request newRequest = request.newBuilder().url(httpUrl).build(); return chain.proceed(newRequest); } }添加什么拦截都是实现InterceptorInterceptor接口,然后去里面拿到Request去按需求做你的操作,大部分都是套路代码,写一个遍会了就会了,最后别忘记了把这个拦截器设置给OkHttpClient
完整的代码贴下:
public void append_url_by_interceptor(View view){ OkHttpClient httpClient = new OkHttpClient(); if (BuildConfig.DEBUG) { HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); logging.setLevel(HttpLoggingInterceptor.Level.BODY); //统一在url后面添加参数 AppendUrlParamInterceptor appendUrlParamInterceptor = new AppendUrlParamInterceptor(); httpClient = new OkHttpClient.Builder().addInterceptor(logging).addInterceptor(appendUrlParamInterceptor).build(); } Retrofit retrofit = new Retrofit.Builder() .client(httpClient) .baseUrl("http://gank.io") .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); KSService service = retrofit.create(KSService.class); Observable<ResponseBody> observable = service.getInfoDataByRxjava("Android","10",1); observable .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer<ResponseBody>(){ @Override public void accept(ResponseBody responseBody) throws Exception { String s = responseBody.string(); Log.e(TAG,"请求的结果:"+s); } }); }现在查看log,到底有没有成功
刚才是用get请求方式,那么post请求方式可以么,试试就知道了,
现在定义一个方法去请求我们服务器
@FormUrlEncoded @POST("aa/HelloServlet") Observable<ResponseBody> appendUrlParamByInterceptor(@FieldMap Map<String,String> map);实现
public void append_url_by_post(View view){ OkHttpClient httpClient = new OkHttpClient(); if (BuildConfig.DEBUG) { HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); logging.setLevel(HttpLoggingInterceptor.Level.BODY); //统一在url后面添加参数 AppendUrlParamInterceptor appendUrlParamInterceptor = new AppendUrlParamInterceptor(); httpClient = new OkHttpClient.Builder().addInterceptor(logging).addInterceptor(appendUrlParamInterceptor).build(); } Retrofit retrofit = new Retrofit.Builder() .client(httpClient) .baseUrl("http://192.168.1.107:8080/") .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); KSService service = retrofit.create(KSService.class); Map<String,String> map = new HashMap<>(); map.put("username","zhouguizhi"); map.put("pwd","123456"); Observable<ResponseBody> observable = service.appendUrlParamByInterceptor(map); observable .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer<ResponseBody>(){ @Override public void accept(ResponseBody responseBody) throws Exception { String json = responseBody.string(); Log.e(TAG,"请求的结果:"+json); } }); }看下我服务端端额控制台信息
然后看下客户端的log:
可以看到是post请求,然后是第一次url请求地址也出来了,拦截了后,我们追加的请求参数也打印出来了,
Header统一添加参数
还是用刚才的那个请求,统一添加请求头自定义拦截器如下:
public class AppendHeaderParamInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request();//拿到发送的请求 Headers headers = request.headers().newBuilder().add("token","mytoken").build(); Request newRequest = request.newBuilder().headers(headers).build(); return chain.proceed(newRequest); } }实现:
public void append_header(View view){ OkHttpClient httpClient = new OkHttpClient(); if (BuildConfig.DEBUG) { HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); AppendHeaderParamInterceptor header = new AppendHeaderParamInterceptor(); logging.setLevel(HttpLoggingInterceptor.Level.BODY); //统一添加请求header httpClient = new OkHttpClient.Builder().addInterceptor(logging) .addInterceptor(header) .build(); } Retrofit retrofit = new Retrofit.Builder() .client(httpClient) .baseUrl("http://192.168.1.107:8080/") .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); KSService service = retrofit.create(KSService.class); Map<String,String> map = new HashMap<>(); map.put("username","zhouguizhi"); map.put("pwd","123456"); Observable<ResponseBody> observable = service.appendUrlParamByInterceptor(map); observable .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer<ResponseBody>(){ @Override public void accept(ResponseBody responseBody) throws Exception { String json = responseBody.string(); Log.e(TAG,"请求的结果:"+json); } }); }观察我服务端打印的请求header头数据
现在看客户端的log:
无网络统一处理
之前项目无网络都是每个接口手动去判断,如果你做了封装的话还好点,至少只要判断一次就行了,而不是等请求发送出去了以后,回来发现给你一个提示无网络或者什么的,我们在请求之前就统一检查网络并处理
还是和以前一样,自定义拦截器,
public class HandleNoNetInterceptor implements Interceptor { private Context content; public HandleNoNetInterceptor(Context content) { this.content = content; } @Override public Response intercept(Chain chain) throws IOException { if(NetUtils.isNetworkAvalible(content)){ return chain.proceed(chain.request()); }else{ Handler handler = new Handler(Looper.getMainLooper()); handler.post(new Runnable() { @Override public void run() { Toast.makeText(content,"网络异常,请检查你的网络",Toast.LENGTH_LONG).show(); } }); throw new RuntimeException("网络异常了~~~~~"); } } }因为我们在发送网络请求的时候,是放在子线程中,所以你不使用handler post这个toast是无法出来的,如果是使用rxjava,他有个onError在这里可以做针对你的需求做处理,
OkHttpClient httpClient = new OkHttpClient(); if (BuildConfig.DEBUG) { HandleNoNetInterceptor handleNoNetInterceptor =new HandleNoNetInterceptor(this); HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); logging.setLevel(HttpLoggingInterceptor.Level.BODY); //统一添加请求header httpClient = new OkHttpClient.Builder() .addInterceptor(logging) .addInterceptor(handleNoNetInterceptor) .build(); } Retrofit retrofit = new Retrofit.Builder() .client(httpClient) .baseUrl("http://192.168.1.107:8080/") .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); KSService service = retrofit.create(KSService.class); Map<String,String> map = new HashMap<>(); map.put("username","zhouguizhi"); map.put("pwd","123456"); Observable<ResponseBody> observable = service.appendUrlParamByInterceptor(map); observable .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<ResponseBody>() { @Override public void onSubscribe(@NonNull Disposable d) { } @Override public void onNext(@NonNull ResponseBody responseBody) { } @Override public void onError(@NonNull Throwable e) { Log.e(TAG,"异常消息:"+e.getLocalizedMessage()); } @Override public void onComplete() { } });千万别忘记了添加权限:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
缓存设置
也是要自定义拦截器的,
public class CacheInterceptor implements Interceptor { private Context context; public CacheInterceptor(Context context) { this.context = context; } @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); //这是在没网的时候设置缓存 if(!NetUtils.isNetworkAvalible(context.getApplicationContext())){ Request cacheRequest = request.newBuilder() .cacheControl(CacheControl.FORCE_CACHE) .build(); return chain.proceed(cacheRequest); } Response cacheResponse = chain.proceed(request); long cacheMaxTime = 1*60*60;//缓存1小时 return cacheResponse.newBuilder() .header("Cache-Control", "public, only-if-cached, max-stale="+cacheMaxTime) .removeHeader("Pragma") .build(); } }我这是请求http://www.qq.com,这个缓存必须要服务器支持,如果服务器不支持的话,是会报错的,
HTTP 504 Unsatisfiable Request (only-if-cached)我刚开始就遇到了这个问题,网上查了下.
请求的方法
@GET Observable<ResponseBody> request_qq(@Url String url);最终的实现
public void cache_set(View view){ OkHttpClient httpClient = new OkHttpClient(); if (BuildConfig.DEBUG) { HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); logging.setLevel(HttpLoggingInterceptor.Level.BODY); long cacheSize = 1024*1024*6; Cache cache = new Cache(new File(FileUtil.getPath(),"cache_content"),cacheSize); httpClient = new OkHttpClient.Builder().cache(cache) .addInterceptor(logging) .addInterceptor(new CacheInterceptor(this)) .build(); } Retrofit retrofit = new Retrofit.Builder() .client(httpClient) .baseUrl("http://192.168.1.107:8080/") .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); KSService service = retrofit.create(KSService.class); Observable<ResponseBody> observable = service.request_qq("http://www.qq.com"); observable .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<ResponseBody>() { @Override public void onSubscribe(@NonNull Disposable d) { } @Override public void onNext(@NonNull ResponseBody responseBody) { } @Override public void onError(@NonNull Throwable e) { } @Override public void onComplete() { } }); }查看我缓存的文件,在sd下的cache_content文件:
打开缓存文件;
这是需要服务器支持缓存的,如果你服务器不支持缓存,但是你在没网的时候又想缓存的数据,就要自己搞了,
超时,错误重试机制
这个和okHttp一样的,废话本来底层网络就是用okhttp.
.connectTimeout(15, TimeUnit.SECONDS) .readTimeout(15,TimeUnit.SECONDS) .writeTimeout(15,TimeUnit.SECONDS) .retryOnConnectionFailure(true)还有个多文件上传,还没弄,这个后期补上,就写到这里吧.