Retrofit2的学习使用

1、添加依赖

implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
implementation('com.github.ihsanbal:LoggingInterceptor:3.1.0') {
        exclude group: 'org.json', module: 'json'
    }

2、建立接口

public interface ApiServer {

    //普通的post请求
    @POST("api/v1/face_client/hotel_room/device/heart.htm")
    Call getG2Api(@Body S2 s2);


    //单文件上传
    @Multipart
    @POST("api/v1/face_client/hotel_room/device/upload_attachment.htm")
    Call sendFileApi(@Part("hardwareId")String hardwareId, @Part("commandId")int commandId, @Part("type")int type, @Part MultipartBody.Part file);
}

3、创建retrofit实例

public class RetrofitUtils {
    private static RetrofitUtils INSTANCE;
    private Retrofit retrofit;

    private RetrofitUtils() {
        LoggingInterceptor httpLoggingInterceptor = new LoggingInterceptor.Builder()
                .loggable(BuildConfig.DEBUG)
                .setLevel(Level.BASIC)
                .log(Platform.INFO)
                .request("Request")
                .response("Response")
                .build();

        OkHttpClient client = new OkHttpClient().newBuilder()
                .addInterceptor(httpLoggingInterceptor)//添加日志拦截器方式1
                .addInterceptor(new Interceptor() {//添加头部拦截器
                    @Override
                    public Response intercept(Chain chain) throws IOException {
                        Request request =  chain.request()
                                .newBuilder()
                                .addHeader("Content-Type","application/json")
                                .addHeader("App-Id",Content.headerAppId)
                                .addHeader("Hardware-Id", DeviceUtils.getSerialNumber())
                                .addHeader("Device-Sign",getSign())
                                .build();

                        return chain.proceed(request);
                    }
                }).build();


        retrofit = new Retrofit.Builder().baseUrl("https://test/")
                .addConverterFactory(GsonConverterFactory.create())//设置数据解析器
                .client(client)
                .build();
    }

    public static RetrofitUtils getInstance() {
        if (INSTANCE == null) {
            synchronized (RetrofitUtils.class) {
                if (INSTANCE == null) {
                    INSTANCE = new RetrofitUtils();
                }
            }
        }
        return INSTANCE;
    }


    public  T create(Class service) {
        return retrofit.create(service);
    }


    public String getSign(){
        return MD5Utils.md5("AppId=" + Content.headerAppId + "&HardwareId=" + DeviceUtils.getSerialNumber() + "&AppSecret=test");
    }

}

4、代码调用retrofit

public static void getG2(){
        S2 s2 = new S2();
        s2.setHardwareId(DeviceUtils.getSerialNumber());
        s2.setVersion("1.0");
        ApiServer apiServer = RetrofitUtils.getInstance().create(ApiServer.class);
        apiServer.getG2Api(s2).enqueue(new Callback() {
            @Override
            public void onResponse(Call call, Response response) {
                if (response.code()==200) {
                    G2 body = response.body();
                    Log.e("ysl--",body.toString());
                }else{
                    Log.e("ysl--",response.code()+"");
                }

            }

            @Override
            public void onFailure(Call call, Throwable t) {
                Log.e("ysl==",t.toString());
            }
        });
    }


    public static void sendFileToServer(){
        ApiServer apiServer = RetrofitUtils.getInstance().create(ApiServer.class);
        File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/hotel/run-logs/debug/run.log");
        RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);
        MultipartBody.Part body = MultipartBody.Part.createFormData("file", file.getName(), requestFile);
        apiServer.sendFileApi(DeviceUtils.getSerialNumber(),1,1,body).enqueue(new Callback() {
            @Override
            public void onResponse(Call call, Response response) {
                if (response.code()==200) {
                    Log.e("ysl--",response.toString());
                }else{
                    Log.e("ysl--",response.code()+"");
                }
            }

            @Override
            public void onFailure(Call call, Throwable t) {
                Log.e("ysl==",t.toString());
            }
        });
    }

以下部分摘抄 隔壁老李头 的文档,方便自己记忆及学习

注解详解
1、方法注解:@GET @POST、@PUT、@DELETE、@PATCH、@OPTIONS、@HTTP
2、标记注解:@FormUrlEncoded、@Multipart、@Streaming
3、参数注解:@Query 、@QueryMap、@Body、@Field、@FieldMap、@Part、@PartMap
4、其它注解:@Path、@Header、@Headers、@Url

(一)、方法注解:
1、@GET:用于发送一个get请求
@GET 注解一般必须添加相对路径或者绝对路径或者全路径,如果不想用在@GET 注解后添加请求路径,则可以在方法的第一个参数中用@Url 添加请求路径。
2、@POST:用于发送一个POST请求
@POST 注解一般必须添加相对路径或绝对路径或者全路径,如果不想在@POST 后添加请求路径,则可以在方法的第一个参数用@Url 注解添加请求路径。
3、@PUT:用于发送一个PUT请求
@PUT 注解一般必须添加相对路径或者绝对路径或者全路径,如果不想在PUT注解后添加请求路径,则可以在方法的第一个参数用@Url 注解添加请求路径。
4、@DELETE:用于发送一个DELETE请求
@DELETE 注解 一般必须添加相对路径或者绝对路径或者全路径,如果不想在DELETE注解后添加请求路径,则可以在方法的第一个参数中用@Url 注解添加请求路径。
5、@PATCH:用于发送一个PATCH请求
@PATCH 注解 一般必须添加相对路径或绝对路径或者全路径,如果不想在PATCH注解后添加请求路径,则可以在方法的第一恶参数用@Url 注解添加请求路径
6、@OPTIONS:用于发送一个OPTIONS请求
@OPTIONS 注解一般必须添加相对路径或绝对路径或者全路径,如果不想在OPTIONS注解后添加请求路径,则可以在方法的第一个参数用@Url 注解添加请求路径。
7、@HTTP:作用于方法,用于发送一个自定义的HTTP

(二)、标记注解:
1、@FormUrlEncoded:用于修饰Fiedl注解 和FileldMap注解
使用该注解,表示请求正文将使用表单网址编码。字段应该声明为参数,并用@Field 注解和 @FieldMap 注解,使用@FormUrlEncoded 注解的请求将具有"application/x-www-form-urlencoded" MIME类型。字段名称和值将先进行UTF-8进行编码,再根据RFC-3986进行URI编码。
2、@Multipart:作用于方法
使用该注解,表示请求体是多部分的,每个部分作为一个参数,且用Part注解声明。
3、@Streaming:作用于方法
未使用@Straming 注解,默认会把数据全部载入内存,之后通过流获取数据也是读取内存中数据,所以返回数据较大时,需要使用该注解。
处理返回Response的方法的响应体,用于下载大文件

三)、参数注解
1、@Query:作用于方法参数,用于添加查询参数,即请求参数
参数值通过String.valueOf()转换为String 并进行URL编码,使用该注解定义的参数,参数值可以为空,为空时,忽略该值,当传入一个List或array时,为每个非空item拼接请求键值对,所有的键是统一的,如:name=张三&name=李四&name=王五。

2、@QueryMap:作用于方法的参数
以map的形式添加查询参数,即请求参数,参数的键和值都通过String.valueOf()转换为String格式。默认map的值进行URL编码,map中的每一项发键和值都不能为空,否则跑出IllegalArgumentException异常。

3、@Body:作用于方法参数
使用@Body 注解定义的参数不能为null
当你发送一个post或put请求,但是又不想作为请求参数或表单的方式发送请求时,使用该注解定义的参数可以直接传入一个实体类,retrofit会通过convert把该实体序列化并将序列化的结果直接作为请求体发送出去
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

4、@Field:作用于方法的参数
用String.valueOf()把参数值转换为String,然后践行URL编码,当参数值为null是=时,会自动忽略,如果传入的是一个List或者array,则为每一个非空的item拼接一个键值对,每一个键值对中的键是相同的,值就是非空的item的值。如:name=张三&name=李四&name=王五,如果itme的值有空格,在拼接的时候会自动忽略,例如某个item的值为:张 三,则拼接后为name=张三

5、@FieldMap:作用于方法的参数
map中的每一项的键和值都不能为空,否则抛出IllegalArgumentException异常。

6、@Part:作用于方法的参数,用于定义Multipart请求的每和part
使用该注解定义的参数,参数值可以为空,为空时,则忽略。使用该注解定义的参数类型有如下3中方式可选:
1 okhttp2.MulitpartBody.Part,内容将被直接使用。省略part中的名称,即@Part MultipartBody.Part part
2 如果类型是RequestBody,那么该值直接与其内容类型一起使用。在注释中提供part名称(例如,@Part("foo") RequestBody foo)
3 其它对象类型将通过使用转换器转换为适当的格式。在注释中提供part名称(例如,@Part("foo") Image photo

7、@PartMap:作用于方法的参数
以map的方式定义Multipart请求的每个part map中每一项的键和值都不能为空,否则抛出IllegalArgumentException异常。
使用@PartMap 注解定义的参数类型有一下两种:
1 如果类型是RequestBody,那么该值将直接与其内容类型与其使用。
2 其它对象类型将通过使用转换器转换为适当的格式。

(四)其他注解:
1、@Path:用于方法的参数
在URL路径中替换指定参数值。使用String.valueOf()和URL编码将值转换为字符串。
使用@Path 注解 定义的参数的值不能为空,参数值默认使用URL编码。
2、@Header:作用于方法的参数,用于添加请求头
使用 @Header 注解 定义的请求头可以为空,当为空时,会自动忽略,当传入一个List或者array时,为拼接每个非空的item的值到请求头中。
具有相同名称的请求头不会相互覆盖,而是照样添加到请求头中

@GET("/")
Call foo(@Header("Accept-Language") String lang);

3、@Headers:作用于方法,用于添加一个或多个请求头中
具有相同名称的请求头不会相互覆盖,而是会照样添加到请求头中。
示例如下:

//添加一个请求头
 @Headers("Cache-Control: max-age=640000")
 @GET("/")

//添加多个请求头
@Headers({ "X-Foo: Bar", "X-Ping: Pong"})
@GET("/")

4、@Url: 作用于方法参数
用于添加请求的接口地址:
代码如下:

@GET
Call list(@Url String url);

(四)注意事项:
1、Map用来组合复杂的参数,并且对于FieldMap,HeaderMap,PartMap,QueryMap这四种作用方法的注解,其参数类型必须为Map实例,且key的类型必须为String类型,否则抛出异常。
2、Query、QueryMap与Field、FieldMap功能一样,生成的数据形式一样;Query、QueryMap的数据体现在Url上;Field、FieldMap的数据是请求体
3、{占位符}和PATH尽量只用在URL的path部分,url的参数使用Query、QueryMap代替,保证接口的简洁
4、Query、Field、Part支持数据和实现了iterable接口的类型,如List、Set等,方便向后台传递数组,代码如下:
5、以上部分注解真正的实现在ParameterHandler类中,每个注解的真正实现都是ParameterHandler类中的一个final类型的内部类,每个内部类都对各个注解的使用要求做了限制,比如参数是否可空、键和值是否可空等。
6、@FormUrlEncoded 注解和@Multipart 注解不能同时使用,否则会抛出methodError(“Only one encoding annotation is allowed.”),可在ServiceMethod类中parseMethodAnnotation()方法中找到不能同时使用的具体原因。
7、@Path 与@Url 注解不能同时使用,否则会抛出parameterError(p, "@Path parameters may not be used with @Url."),可在ServcieMethod类中parseParameterAnnotation()方法中找到不能同时使用的具体代码。其实原因也是很好理解:Path注解用于替换url中的参数,这就要求在使用path注解时,必须已经存在请求路径。不然没法替换路径中指定的参数。而@Url 注解是在参数中指定了请求路径的,这时候情定请求路径已经晚,path注解找不到请求路径,更别提更换请求路径了中的参数了。
8 使用@Body 注解的参数不能使用form 或multi-part编码,即如果为方法使用了FormUrlEncoded或Multipart注解,则方法的参数中不能使用@Body 注解,否则会抛出异常parameterError(p, “@Body parameters cannot be used with form or multi-part encoding.”)

你可能感兴趣的:(Retrofit2的学习使用)