美文网首页
开源库Retrofit

开源库Retrofit

作者: 30cf443c3643 | 来源:发表于2018-11-06 11:22 被阅读15次

    Retrofit是square公司对网络请求okhttp的二次封装,通过注解反射的方式,配置网络请求的参数,支持多种返回数据格式解析,支持同步异步调用。
    这是一份很详细的 Retrofit 2.0 使用教程里面很详细的讲了注解,数据解析器,网络请求适配。基础的知识都很容易,标记一些比较容易忽视的内容

    @FormUrlEncoded 每个键值对需要用@Filed来注解键名,随后的对象需要提供值。否则会报错
    @Multipart表示发送form-encoded的数据(适用于 有文件 上传的场景)

    
    @Multipart
    @POST("mobile/upload")
    Call<ResponseBody> upload(@Part MultipartBody.Part file);
    ------------------------------------------------------------------------------------------------------
    // 创建 RequestBody,用于封装 请求RequestBody
    RequestBody requestFile =
            RequestBody.create(MediaType.parse("image/jpg"), file);
     //  image/jpg是我们要上传的文件类型,你总得告诉别人你传的文件是什么格式的对吧,对应了请求体中的Content-Type: image/jpeg
    // MultipartBody.Part is used to send also the actual file name
    MultipartBody.Part body =
            MultipartBody.Part.createFormData("file", file.getName(), requestFile);
    -----------------------------------------------------------------------------------------------------
    // 添加描述  Http是只能进行纯文本传输,所以在后来支持文件上传后,新增了一个MIME类型,叫multipart/form-data。
    //上传文件时  Content-Type:multipart/form-data;同时有boundary分隔上传的内容
    String descriptionString = "hello, 这是文件描述";
    RequestBody description =
            RequestBody.create(
                    MediaType.parse("multipart/form-data"), descriptionString);
    
    -----------------------------------------------------------------------------------------------------
    

    @Headers
    Retrofit提供了两种方式来定义HTTP请求头:静态和动态。
    静态通过添加注解的方式

    public interface WeatherService {
        @Headers("apikey:b86c2269fe6588bbe3b41924bb2f2da2")
        @GET
        Call<WeatherWrapper> weather(@Url String url, @Query("cityname") String cityName);
    }
    

    或者动态添加方法参数的方式

    @GET
    Call<WeatherWrapper> weather(@HeaderMap Map<String, String> headers, @Url String url, @Query("cityname") String cityName);
    
    

    添加拦截器

    在OkHttp中Interceptors拦截器是一种强大的机制,可以监视,重写和重试Call请求


    20170529175638399.png

    拦截器分为应用拦截器和网络拦截器

    添加日志拦截器

    class LoggingInterceptor implements Interceptor {
            @Override
            public Response intercept(Interceptor.Chain chain) throws IOException {
                Request request1 = chain.request();
    
                long t1 = System.nanoTime();
                Log.d("tag",String.format("Sending request %s on %s%n%s",
                        request1.url(), chain.connection(), request1.headers()));
    
                Response response = chain.proceed(request1);
    
                long t2 = System.nanoTime();
                Log.d("tag",String.format("Received response for %s in %.1fms%n%s",
                        response.request().url(), (t2 - t1) / 1e6d, response.headers()));
    
                return response;
            }
        }
    
    //同时通过配置okhttpclient添加网络拦截器
    
     OkHttpClient.Builder builder = new OkHttpClient.Builder()
                    .connectTimeout(5, TimeUnit.SECONDS)//设置超时时间
                    .addNetworkInterceptor(new LoggingInterceptor())
                    .retryOnConnectionFailure(true);
            OkHttpClient client=builder.build();
    
    
            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl(Config.BASE_URL)
                    .client(client)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
            mApiService = retrofit.create(ApiService.class);
    

    测试得到结果


    2018-11-05_160239.png

    同样 可以通过添加拦截器来添加请求头

    okHttpClientBuilder.addInterceptor(new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request original = chain.request();
            Request.Builder requestBuilder = original.newBuilder()
                    .header("platform", "platform")//平台
                    .header("sysVersion", "sysVersion")//系统版本号
                    .header("device", "device")//设备信息
                    .header("screen", "screen")//屏幕大小
                    .header("uuid", "uuid")//设备唯一码
                    .header("version", "version")//app版本
                    .header("apiVersion", "apiVersion")//api版本
                    .header("token", "token")//令牌
                    .header("channelId", "channelId")//渠道
                    .header("networkType", "networkType");//网络类型
            Request request = requestBuilder.build();
            return chain.proceed(request);
        }
    });
    
    

    还有通过添加缓存拦截器来实现无缓存功能

    public class CacheInterceptor implements Interceptor {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            if (!NetUtil.isNetworkConnected()) {//没网强制从缓存读取(必须得写,不然断网状态下,退出应用,或者等待一分钟后,就获取不到缓存)
                request = request.newBuilder()
                        .cacheControl(CacheControl.FORCE_CACHE)
                        .build();
            }
            Response response = chain.proceed(request);
            if (NetUtil.isNetworkConnected()) {//有网情况下,从服务器获取
                int maxAge = BuildConfig.DEFAULT_COOKIE_NETWORK_TIME;
                // 有网络时, 缓存最大保存时长为60s
                response.newBuilder()
                        .header("Cache-Control", "public, max-age=" + maxAge)
                        .removeHeader("Pragma")
                        .build();
            } else {//没网情况下,一律从缓存获取
                // 无网络时,设置超时为30天
                int maxStale = BuildConfig.DEFAULT_COOKIE_NO_NETWORK_TIME;
                response.newBuilder()
                        .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
                        .removeHeader("Pragma")
                        .build();
            }
            return response;
        }
    

    CallAdapter

    我们知道通过添加RxJavaCallAdapter可以将call类型编程observer类型。那么如何去变成其他类型呢?在Architecture Components的代码中就有例子,将call类型装换成livedata<ApiResponse>的示例,ApiResponse是一个判断网络请求是否成功的类

    public class LiveDataCallAdapter<R> implements CallAdapter<R,LiveData<ApiResponse<R>>> {
        private final Type responseType;
        public LiveDataCallAdapter(Type responseType) {
            this.responseType = responseType;
        }
        @Override
        public Type responseType() {
            return responseType;
        }
    
        @Override
        public LiveData<ApiResponse<R>> adapt(final Call<R> call) {
            return new LiveData<ApiResponse<R>>() {
                private AtomicBoolean started = new AtomicBoolean(false);//boolean的原子类型
                @Override
                protected void onActive() {
                    super.onActive();
                    if (started.compareAndSet(false,true)){    //compareAndSet预期arg0跟started是否一致,一致则started赋值为arg1;返回值实际上是是否成功修改
                        call.enqueue(new Callback<R>() {
                            @Override
                            public void onResponse(Call<R> call, Response<R> response) {
                                postValue(new ApiResponse<>(response));
                            }
    
                            @Override
                            public void onFailure(Call<R> call, Throwable t) {
                                postValue(new ApiResponse<R>(t));
                            }
                        });
                    }
                }
            };
        }
    }
    ---------------------------------------------------------------------------------------------------------
    
    public class LiveDataCallAdapterFactory extends CallAdapter.Factory {
    
        @Override
        public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
            if (getRawType(returnType) != LiveData.class) {
                return null;
            }
            Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
            Class<?> rawObservableType = getRawType(observableType);
            if (rawObservableType != ApiResponse.class) {
                throw new IllegalArgumentException("type must be a resource");
            }
            if (! (observableType instanceof ParameterizedType)) {
                throw new IllegalArgumentException("resource must be parameterized");
            }
            Type bodyType = getParameterUpperBound(0, (ParameterizedType) observableType);
            return new LiveDataCallAdapter<>(bodyType);
        }
    }
    

    相关文章

      网友评论

          本文标题:开源库Retrofit

          本文链接:https://www.haomeiwen.com/subject/ynrsxqtx.html