Retrofit入门教程

前言

现在的网络请求开源项目层出不穷,优秀者也不胜枚举。常用的Volley,OkHttp等等。层出不穷的优秀开源工具,使得开发者的开发效率大幅提高,并且更加专注于自身的业务。今天介绍一下Retrofit的基本使用方法。

声明在前

由于retrofit1.x和retrofit2.x升级变化很大,而有些教程在进行知识讲解时并未之处针对的retrofit版本,这一点很让初学者头痛。现在您将看到的是关于retrofit2.x的讲解。另外,关于retrofit1.x和retrofit2.x推荐一个不错的网站:https://futurestud.io,该网站关于retrofit1.x有详细的系列讲解,并且文章也出了retrofit2.x系列,且没有删除retrofit1.x的相关讲解。非常的不错,可惜的是英文的。retrofit2使用了其默认的okhttpClient,当然你也可以自定义client。不过此时你需要关联OkHttp。

闲聊retrofit

函数式编程使得代码更易于阅读,更加直观、简洁。retrofit也借鉴了这方面的有点。这是一个比较好的趋势。与此同时,注解在retrofit的大量应用,使得网络请求变得更加轻量级。大大减少了工作量,例如GET, POST, PUT, DELETE, 和 HEAD的请求参数都可以通过注解的方式来实现。retrofit涵盖了主要的网络请求方式。

另外,如果想要更深入的学习retrofit,对注解,反射的掌握是前提条件,如果想要更深入,还要学习一下java的动态代理技术。

retrofit的使用

首先需要将http api定义在接口中


public interface GitHubService {
  @GET("users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);
}

其中Get注解代表这是一个get请求,大括号{}包含了请求api的可变部分。在listRepos中通过注解指定get请求路径中的可变参数user。这是一个比较简单的api接口。稍后会列出一些混合的复杂的接口实现。List是请求回的数据的封装。

直接使用

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();

GitHubService service = retrofit.create(GitHubService.class);

通过被创建的GitHubService可以调用call方法实现一个同步或者异步的网络请求:

Call<List<Repo>> repos = service.listRepos("octocat");

一些复杂的请求接口

添加请求参数

@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);

添加多个请求参数

@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);

指定请求头

方式一:

@Headers({
    "Accept: application/vnd.github.v3.full+json",
    "User-Agent: Retrofit-Sample-App"
})
@GET("users/{username}")
Call<User> getUser(@Path("username") String username);

方式二:

@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)

以上请求都是同步的;
如果使用异步网络请求,需要在以上网路接口中增加一个回调例如:

@GET("/user/{id}/photo")
void getUserPhoto(@Path("id") int id, Callback<Photo> cb);

序列化方式

默认的是RequestBody和ResponseBody
另外提供了以下converter

Gson - com.squareup.retrofit2:converter-gson
Jackson - com.squareup.retrofit2:converter-jackson
Moshi - com.squareup.retrofit2:converter-moshi
Protobuf - com.squareup.retrofit2:converter-protobuf
Wire - com.squareup.retrofit2:converter-wire
Simple Framework - com.squareup.retrofit2:converter-simpleframework
Scalars - com.squareup.retrofit2:converter-scalars


附录:官方教程

到底怎么使用Retrofit呢?

Retrofit通过注解动态代理来进行网络请求。所以充分了解Retrofit的注解非常的重要:
这里写图片描述
上图是Retrofit中关于网络请求相关的所有注解。

例如想要添加请求头

如果你想添加请求头:
retrofit提供了HEAD和Header和Headers三个注解,供你使用。
关于HEAD:

@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface HEAD {
    String value() default "";
}

请注意HEAD是用在方法的注解的。但这是请求头参数较少的请求。此外还可以使用Header

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface Header {
    String value();
}

Header是用在参数中的。

再说说Headers上面已经提供了一个service实例。
看看源码:

@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Headers {
    String[] value();
}

所以无论你的请求想要添加什么参数,先查看一下retrofit关于注解的源码:

关于@Target的类型

  • CONSTRUCTOR:用于描述构造器
  • FIELD:用于描述域
  • LOCAL_VARIABLE:用于描述局部变量
  • METHOD:用于描述方法
  • PACKAGE:用于描述包
  • PARAMETER:用于描述参数
  • TYPE:用于描述类、接口(包括注解类型) 或enum声明

了解到这儿,至少你应该具有独立使用retrofit的能力了。

作为扩展知识,还是希望能研究一下retrofit的源码。另外推荐一下Rxjava。二者结合使用,效率更高啊!

优秀文章:

Retrofit2.0使用总结及注意事项

关于retrofit的一个坑爹的提示

这个提示可能称不上是bug,先来描述一下这个提示:

can't resolve host在github的issues里面找了好久也没找到合适的答案,由于我的手机设置了代理,当我取消代理时,这个问题就解决了。真是好坑啊!!!!!!!!!!!!!!!!!

使用案例

案例1:为请求添加头

可以通过添加注解@Headers在endpoint上,也可以通过okhttp的插入器,来进行添加头。

通过@Headers来添加头

这个例子很好找,在retrofit的官方介绍中:


@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
Call<List<Widget>> widgetList();

通过okhttp的插入器实现

okHttpClient.interceptors().add(new Interceptor() {  
    @Override
    public Response intercept(Interceptor.Chain chain) throws IOException {
        Request original = chain.request();

        // Request customization: add request headers
        Request.Builder requestBuilder = original.newBuilder()
                .header("Authorization", "auth-value"); // <-- this is the important line

        Request request = requestBuilder.build();
        return chain.proceed(request);
    }
});

不过此时要注意Request.Builder的header(key,value)和addHeader(key,value)的区别。

.header(key, val): will override preexisting headers identified by key//将会覆盖已存在的header
.addHeader(key, val): will add the header and don’t override preexisting ones//将会添加到header而不是覆盖

retrofit2的转换器转换为字符串

这是一个字符串转换器,有来做测试比较方便

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

import okhttp3.MediaType;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Converter;
import retrofit2.Retrofit;
public class ToStringConverterFactory extends Converter.Factory {
    private static final MediaType MEDIA_TYPE = MediaType.parse("text/plain");


    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
        if (String.class.equals(type)) {
            return new Converter<ResponseBody, String>() {
                @Override
                public String convert(ResponseBody value) throws IOException {
                    return value.string();
                }
            };
        }
        return null;
    }

    public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {

        if (String.class.equals(type)) {
            return new Converter<String, RequestBody>() {
                @Override
                public RequestBody convert(String value) throws IOException {
                    return RequestBody.create(MEDIA_TYPE, value);
                }
            };
        }
        return null;
    }
}

一些未知的小事项

最好不要通过插入器修改链接,会造成一些错误的结果,例如:重复修改链接,这个问题有待查明!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章