Retrofit 网络请求框架

1、什么是Retrofit框架?

它是Square公司开发的现在非常流行的网络框架

2.为什么使用Retrofit框架

        性能好,处理快,使用简单,Retrofit 是安卓上最流行的HTTP Client库之一
默认使用OKHttp处理网络请求,我觉得可以看成是OKHttp的增强。默认使用Gson解析.

 怎么配置Retrofit2.0?

//配置retrofit2.0
compile 'com.squareup.retrofit2:retrofit:+'
compile 'com.squareup.retrofit2:converter-gson:+'
//配置支持Rxjava2
compile 'com.squareup.retrofit2:adapter-rxjava2:+'
compile 'io.reactivex.rxjava2:rxjava:+'
compile 'io.reactivex.rxjava2:rxandroid:+'

1.构造Retrofit:

***baseUrl:****

1. 默认的服务器地址,Retrofit在进行请求一个接口时会根据你填写的

baseurl+方法名 去请求。

****addConverterFactory:****

添加返回数据的解析方式,Retrofit支持多种格式的解析,xml,json,

jackson,Moshi,Protobuf,wire等,添加对这些数据格式的支持同样需要在

Gradle中进行依赖。这些依赖Square公司同样提供了支持。

****CallAdapter:****

Retrofit会将网络请求的接口以回调的方式返回,我们通常会得到一个叫做

Call<类型>的结果,如果我们需要返回其他的结果,例如RxJava形式的结果,需

要对RxJava做支持。如果不需要特殊类型的返回结果,我们是不需要配置的。

****Client:****

通过该方法我们可以添加自己定制的OkHttp

 

三、创建接口 声明API

四、 Retrofit各个注解的含义及作用

GET注解
    1. 用于发送一个get请求
    2. GET注解一般必须添加相对路径或绝对路径或者全路径,如果不想在GET注解后添加请求路径,则可以在方法的第一个参数中用@Url注解添加请求路径。

 Url注解:
    1. 作用于方法参数
    2. 用于添加请求的接口地址
    3.示例:

@GET
Call list(@Url String url);

Path注解:
    1. 作用于方法的参数
    2. 在URL路径段中 替换指定的参数值。使用String.valueOf()和URL编码
    3. 将值转换为字符串。
    4. 使值不可为用该注解定义的参数的空
    5. 参数值默认使用URL编码
    6. 示例:
//默认使用URL编码
@GET("/user/{name}")
Call encoded(@Path("name") String name);
//不使用URL编码
@GET("/user/{name}")
Call notEncoded(@Path(value="name", encoded=true) String name);

 Query注解:
     1. 作用于方法的参数
     2. 用于添加查询参数,即 请求参数
     3. 参数值通过String.valueOf()转换为String并进行URL编码
     4. 使用该注解定义的参数,参数值 可以为空,为空时,忽略该值,当传入一个Listarray时,为每个非空item拼接请求键值对,所有的键是统一的,如:name=张三&name=李&name=王五.
     5. 示例:
@GET("/list")
Call list(@Query("page") int page);
@GET("/list")
Call list(@Query("category") String category);
//传入一个数组
@GET("/list")
Call list(@Query("category") String... categories);
//不进行URL编码
@GET("/search")
Call list(@Query(value="foo", encoded=true) String foo);

 QueryMap注解:
     1. 作用于方法的参数
     2. 以 map的形式添加查询参数,即请求参数
     3. 参数的键和值都通过String.valueOf()转换为String格式
     4. map的键和值默认进行URL编码
     5. map中每一项的 键和值都不能为空,否则抛IllegalArgumentException异常
     6. 示例:
//使用默认URL编码
@GET("/search")
Call list(@QueryMap Map filters);
//不使用默认URL编码
@GET("/search")
Call list(@QueryMap(encoded=true) Map filters);

POST注解:
    1. 用于发送一个POST请求
    2. POST注解一般必须添加相对路径或绝对路径或者全路径,如果不想在POST注解后添加请求路径,则可以在方法的第一个参数中用@Url注解添加请求路径

FormUrlEncoded注解:
    1. 用于修饰Field注解和FieldMap注解
    2. 使用该注解,表示请求正文将使用表单网址编码。字段应该声明为参数,并用@Field注释或FieldMap注释。使用FormUrlEncodied注解的请求将具”applicaton / x-www-form-urlencoded” MIME类型

Field注解
     1. 作用于方法的参数
     2. 用于发送一个表单请求

@FormUrlEncoded
@POST("/")
Call example(@Field("name") String name,@Field("occupation") String
        occupation);
//固定或可变数组
@FormUrlEncoded
@POST("/list")
Call example(@Field("name") String... names);

 FieldMap注解:
    1. 作用于方法的参数
    2. 用于发送一个表单请求
    3. map中每一项的键和值都不能为空,否则抛出IllegalArgumentException异常
@FormUrlEncoded
@POST("/things")
Call things(@FieldMap Map fields);

 Header注解:
    1. 作用于方法的参数,用于添加请求头
    2. 使用该注解定义的请求头可以为空,当为空时,会自动忽略,当传入一个List或array时,为拼接每个非空的item的值到请求头中.具有相同名称的请求头不会相互覆盖,而是会照样添加到请求头中
    3. 示例:
@GET("/")
Call foo(@Header("Accept-Language") String lang);

 HeaderMap注解:
     1. 作用于方法的参数,用于添加请求头
     2. 以map的方式添加多个请求头,map中的key为请求头的名称,value为请求头的值,且value使用String.valueOf()统一转换为String类型,map中每一项的 键和值都不能为空,否则抛出IllegalArgumentException异常
     3. 示例:
@GET("/search")
    void list(@HeaderMap Map headers);
    //map
    Map headers = new HashMap()<>;
headers.put("Accept","text/plain");
headers.put("Accept-Charset", "utf-8");

 Headers注解:
    1. 作用于方法,用于添加一个或多个请求头
    2. 具有相同名称的请求头不会相互覆盖,而是会照样添加到请求头中
    3. 示例:
//添加一个请求头
    @Headers("Cache-Control: max-age=640000")
    @GET("/")
...
//添加多个请求头
    @Headers({"X-Foo: Bar",
            "X-Ping: Pong"
    })
    @GET("/")
...

 

2.1 HTTP注解: (了解)
    1. 作用于方法,用于发送一个自定义的HTTP请求
    2. 示例:

//自定义HTTP请求的标准样式
interface Service {
    @HTTP(method = "CUSTOM", path = "custom/endpoint/")
    Call customEndpoint();
}
//发送一个DELETE请求
interface Service {
    @HTTP(method = "DELETE", path = "remove/", hasBody = true)
    Call deleteObject(@Body RequestBody object);
}

Multipart注解:
    1. 作用于方法
    2. 使用该注解,表示请求体是多部分的。 每一部分作为一个参数,且用Part注解声明

 Part注解:
         1. 作用于方法的参数,用于定义Multipart请求的每个part
         2. 使用该注解定义的参数,参数值可以为空,为空时,则忽略
         3. 使用该注解定义的参数类型有以下3种方式可选:
    1, 如果类型是okhttp3.MultipartBody.Part,内容将被直接使用。 省略   part中的名称,即 @Part MultipartBody.Part part
    2, 如果类型是RequestBody,那么该值将直接与其内容类型一起使用。 在注释中提供part名称(例如@Part(“foo”)RequestBody foo)。
    3, 其他对象类型将通过使用转换器转换为适当的格式。 在注释中提供part名称(例如,@Part(“foo”)Image photo)
     4. 示例:
@Multipart
@POST("/")
Call example(
        @Part("description") String description,
        @Part(value = "image", encoding = "8-bit") RequestBody image);

 PartMap注解:
     1. 作用于方法的参数,以map的方式定义Multipart请求的每个partmap中每一项的键和值都不能为空,否则抛出IllegalArgumentException异常
使用该注解定义的参数类型有以下2种方式可选:
     1, 如果类型是RequestBody,那么该值将直接与其内容类型一起使用。
     2, 其他对象类型将通过使用转换器转换为适当的格式。
示例:
@Multipart
@POST("/upload")
Call upload(
        @Part("efile") RequestBody file,
        @PartMap Map params);


3.2 Streaming注解:
     1. 作用于方法
     2. 处理返回Response的方法的响应体,即没有将body()转换为byte[]。 

注意事项:

 

    1,以上部分注解真正的实现在ParameterHandler类中,,每个注解的真正实现都是ParameterHandler类中的一个final类型的内部类,每个内部类都对各个注解的使用要求做了限制,比如参数是否可空,键和值是否可空.

    2,FormUrlEncoded注解和Multipart注解不能同时使用

    3,Path注解与Url注解不能同时使用

    4,对于FiledMap,HeaderMap,PartMap,QueryMap这四种作用于方法的注解,其参数类型必须为Map的实例,且key的类型必须为String类型

    5,使用Body注解的参数不能使用form 或multi-part编码,即如果为方法使用了FormUrlEncoded或Multipart注解,则方法的参数中不能使用Body注解

    6,Retrofit提供了MultiPart注解,说明我们可以上传文件,又提供了Streaming注解,说明我们可以下载文件,我们知道Retrofit可以干这些事,但是我们还是没有办法直接写上传下载代码,这些东西都需要我们自己去封装,这也是为什么目前有很多基于Retrofit构建的二次封装库的原因

 

 

Retrofit 网络请求之@Body标签遇到的坑

https://www.jianshu.com/p/56b5bce47d8c

代码:

/**
 * 封装Retrofit网络请求框架
 * 懒汉式单例模式
 */
public class RetrofitManager {

    public static final String BASE_URL = "http://www.zhaoapi.cn/";
    private final Retrofit retrofit;

    // 静态内部类的单例
    private static final class SINGLE_INSTANCE {
        private static final RetrofitManager _INSTANCE = new RetrofitManager();
    }

    public static RetrofitManager getInstance() {
        return SINGLE_INSTANCE._INSTANCE;
    }

    /**
     * 在构造方法中构造Retrofit对象
     * 设置公共url,解析方式gson,配置OkHttpClient
     */
    private RetrofitManager() {
        // 构造Retrofit对象
        retrofit = new Retrofit.Builder()
                // 设置公共的url部分
                .baseUrl(BASE_URL)
                // 配置解析方式为Gson
                .addConverterFactory(GsonConverterFactory.create())
                // 配置OKHttpClient
                .client(buildOkHttpClient())
                .build();
    }

    @NonNull
    private OkHttpClient buildOkHttpClient() {
        // 构造OkHttpClient对象
        return new OkHttpClient.Builder()
                .readTimeout(5, TimeUnit.SECONDS)
                .writeTimeout(5, TimeUnit.SECONDS)
                .connectTimeout(5, TimeUnit.SECONDS)
                .build();
    }

    /**
     * 因为retrofit在create的时候需要传入class
     * 并且返回这个类
     * @param clazz
     * @param 
     * @return
     */
    public  T create(Class clazz) {
        return retrofit.create(clazz);
    }
}
/**
 * 点击请求网络登录
 * @param view
 */
public void request(View view) {
    // 利用Retrofit.create方法构造一个Api接口的实例
    ILoginApi iLoginApi = RetrofitManager.getInstance().create(ILoginApi.class);

    // 构造一个Call请求,拿到Api接口的实例调用对应的方法去构造一个Call请求
    final Call call = iLoginApi.login("login", "18210926066", "123456");
    /**
     * 异步请求
     */
    call.enqueue(new Callback() {
        @Override
        public void onResponse(Call call, Response response) {
            // 通过response.body拿到最后解析后的bean对象
            LoginBean loginBean = response.body();
            if (loginBean != null && "0".equals(loginBean.getCode())) {
                Toast.makeText(MainActivity.this, "请求成功", Toast.LENGTH_SHORT).show();
            }
        }

        @Override
        public void onFailure(Call call, Throwable t) {
            Toast.makeText(MainActivity.this, "请求失败", Toast.LENGTH_SHORT).show();
        }
    });
}

 

你可能感兴趣的:(Android开发,电商项目进阶)