您的位置:首页 > 移动开发 > Android开发

android retrofit2.0框架的使用介绍

2017-12-04 05:03 453 查看
准备学习下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对应,还是画图说下容易解释



把上面的图翻译下就是这个: /**
* method 表示请的方法,
* path表示路径
* hasBody表示是否有请求体
*/
@HTTP(method = "get", path = "users/{user}", hasBody = false)
这是从网上看到别人写的,觉得对理解起来很不错,就copy过来了,非常感谢,现在对着这个来模仿写一个请求方法
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)还有个多文件上传,还没弄,这个后期补上,就写到这里吧.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: