准备学习下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解析后的beancompile '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> 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 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 call = service.getInfoData("Android","10",1);//传递的参数
第五步:
call.enqueue(new Callback() {    @Override    public void onResponse(Call call, Response response) {        Info info = response.body();        List list = info.getResults();        Log.e(TAG,"url="+list.get(0).getUrl());    }    @Override    public void onFailure(Call call, Throwable t) {    }});

上面就是发送一个异步get的请求,同步我不会再讲了,几乎没人用同步去请求网络,可能第一次写感觉乖乖的,但是多写几次就熟练了.

我们知道get方式请求,我们可以直接把参数拼接在url后面,这样就不用带参数,

@GET("api/data/Android/10/1")Call getInfoData();
还有一种就是如果我们要传的参数有很多,这个时候,就可以使用使用这个注解:@QueryMap
@GET("api/data/")Call getInfoData(@QueryMap Map, String> map);
在传参的时候传递一个map集合就可以了
Map,String> map  = new HashMap<>();map.put("Android","Android");map.put("size","10");map.put("page","1");Call 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 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 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 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 call =  service.login("zhouguizhi","123456");    call.enqueue(new Callback() {        @Override        public void onResponse(Call call, Response response) {                Log.e(TAG,"登录请求成功");            Log.e(TAG,"response="+response.body());        }        @Override        public void onFailure(Call call, Throwable t) {        }    });}
发现报错了,错误日记:


意思是说我们传递的参数没有进行编码,所以post请求一定要加@FormUrlEncoded

@FormUrlEncoded@POST("aa/HelloServlet")Call login(@Field("username")String username, @Field("password") String password);
再试试就成功了,

服务器接受的消息:


客户端接收到的


如果有多个参数也可以使用@FieldMap

文件下载

首先使用get方法从豆瓣上下载一张图片

@GET("/view/photo/m/public/p2505783407.webp")Call 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 call =  service.download_get();    call.enqueue(new Callback() {        @Override        public void onResponse(Call call, Response 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 call, Throwable t) {            Log.e(TAG,"下载失败="+t.getLocalizedMessage());        }    });}
查看日记:


下载成功了我们就到文件管理器中去找下刚才下载的文件


刚才使用get方式文件下载,现在使用post方式文件下载也是一样:

@POST("/view/photo/m/public/p2505783407.webp")Call download_post();
其他代码不变.文件下载好了,开始学习下文件上传,

文件上传

先来个简单的单文件上传

@Multipart@POST("/aa/UploadServlet")Call 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 call =  service.upload_post(body);    call.enqueue(new Callback() {        @Override        public void onResponse(Call call, Response response) {            try {                Log.e(TAG,"文件上传成功="+response.body().string());            } catch (IOException e) {                e.printStackTrace();            }        }        @Override        public void onFailure(Call 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 mulitupload(@Part  MultipartBody.Part file,@QueryMap  Map,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> map = new HashMap<>();    map.put("name","zhouugizhi");    map.put("time","2017-11-30");    Call call =  service.mulitupload(body,map);    call.enqueue(new Callback() {        @Override        public void onResponse(Call call, Response response) {            try {                Log.e(TAG,"文件上传成功="+response.body().string());            } catch (IOException e) {                e.printStackTrace();            }        }        @Override        public void onFailure(Call 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 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 observable =  service.getInfoDataByRxjava("Android","10",1);    observable           .subscribeOn(Schedulers.io())            .observeOn(AndroidSchedulers.mainThread())            .subscribe(new Consumer(){                @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.   *   * 

Example: *

{@code   * --> POST /greeting http/1.1 (3-byte body)   *   * <-- 200 OK (22ms, 6-byte body)   * }
*/ BASIC, /** * Logs request and response lines and their respective headers. * *

Example: *

{@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   * }
*/ HEADERS, /** * Logs request and response lines and their respective headers and bodies (if present). * *

Example: *

{@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   * }
*/ 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 observable =  service.getInfoDataByRxjava("Android","10",1);    observable            .subscribeOn(Schedulers.io())            .observeOn(AndroidSchedulers.mainThread())            .subscribe(new Consumer(){                @Override                public void accept(ResponseBody responseBody) throws Exception {                    String s = responseBody.string();                    Log.e(TAG,"请求的结果:"+s);                }            });}
现在查看log,到底有没有成功


刚才是用get请求方式,那么post请求方式可以么,试试就知道了,

现在定义一个方法去请求我们服务器

@FormUrlEncoded@POST("aa/HelloServlet")Observable appendUrlParamByInterceptor(@FieldMap Map,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> map = new HashMap<>();    map.put("username","zhouguizhi");    map.put("pwd","123456");    Observable observable =  service.appendUrlParamByInterceptor(map);    observable            .subscribeOn(Schedulers.io())            .observeOn(AndroidSchedulers.mainThread())            .subscribe(new Consumer(){                @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> map = new HashMap<>();    map.put("username","zhouguizhi");    map.put("pwd","123456");    Observable observable =  service.appendUrlParamByInterceptor(map);    observable            .subscribeOn(Schedulers.io())            .observeOn(AndroidSchedulers.mainThread())            .subscribe(new Consumer(){                @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> map = new HashMap<>();map.put("username","zhouguizhi");map.put("pwd","123456");Observable observable =  service.appendUrlParamByInterceptor(map);observable        .subscribeOn(Schedulers.io())        .observeOn(AndroidSchedulers.mainThread())        .subscribe(new Observer() {            @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() {            }        });
千万别忘记了添加权限:
android:name="android.permission.INTERNET" />android:name="android.permission.ACCESS_NETWORK_STATE" />android:name="android.permission.ACCESS_WIFI_STATE" />android:name="android.permission.CHANGE_NETWORK_STATE" />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)我刚开始就遇到了这个问题,网上查了下.

请求的方法

@GETObservable 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 observable =  service.request_qq("http://www.qq.com");    observable            .subscribeOn(Schedulers.io())            .observeOn(AndroidSchedulers.mainThread())            .subscribe(new Observer() {                @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)
还有个多文件上传,还没弄,这个后期补上,就写到这里吧.

更多相关文章

  1. Android中关于Volley的使用(三)认识Volley的架构
  2. Android(安卓)自动化测试(6)
  3. Android—网络编程
  4. Android关于RecycleView不走onBindViewHolder和onCreateViewHold
  5. android使用HttpURLConnection上传文件同时提交参数
  6. Android,一个函数实现上传文件(单个,多文件)
  7. android-async-http将json封装到body体中
  8. Android抓包分析-fiddler版
  9. Android(安卓)之事件处理(二)基于监听的事件处理

随机推荐

  1. 如何将加载微调器图像添加到jquery选项卡
  2. JQuery对DOM的操作【三】
  3. Jquery选择带有融合表的标签\复选框
  4. jquery实现简单瀑布流布局
  5. 向下钻取两个步骤,在Highcharts中进行多项
  6. 确定焦点事件:单击或tabstop
  7. 禁用焦点上的锚点()元素上的灰色边框
  8. 触发具有相同类的另一个对象以使用计时器
  9. 关于制作EPG界面的光标聚焦问题(我制作的
  10. Jquery 传json格式数据到后台,后台反序列