Android Retrofit详解

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Retrofit详解相关的知识,希望对你有一定的参考价值。

参考技术A Retrofit 是一个 RESTful 的 HTTP 网络请求框架的封装,网络请求的工作本质上是 OkHttp 完成,而 Retrofit 仅负责 网络请求接口的封装

1.添加Retrofit库的依赖:

后面三个是可选的,分别是数据解析器和gson,以及rxjava支持的依赖

2.创建 用于描述网络请求 的接口
Retrofit将 Http请求 抽象成 Java接口:采用 注解 描述网络请求参数 和配置网络请求参数

3.创建Retrofit实例

4.发送请求
请求分为同步请求和异步请求

response.body()就是Reception对象,网络请求的完整 Url =在创建Retrofit实例时通过.baseUrl()设置 +网络请求接口的注解设置(下面称 “path“ )
整合的规则如下:

上面我们用了@GET注解来发送Get请求,Retrofit还提供了很多其他的注解类型

1.@GET、@POST、@PUT、@DELETE、@HEAD分别对应 HTTP中的网络请求方式
2.@HTTP替换@GET、@POST、@PUT、@DELETE、@HEAD注解的作用 及 更多功能拓展
具体使用:通过属性method、path、hasBody进行设置

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

1.@Header & @Headers
添加请求头 &添加不固定的请求头

2.@Body
以 Post方式 传递 自定义数据类型 给服务器,如果提交的是一个Map,那么作用相当于 @Field,不过Map要经过 FormBody.Builder 类处理成为符合 Okhttp 格式的表单,如:

3.@Field & @FieldMap
发送 Post请求 时提交请求的表单字段,与 @FormUrlEncoded 注解配合使用

4.@Part & @PartMap
发送 Post请求 时提交请求的表单字段,与@Field的区别:功能相同,但携带的参数类型更加丰富,包括数据流,所以适用于 有文件上传 的场景,与 @Multipart 注解配合使用

5.@Query和@QueryMap
用于 @GET 方法的查询参数(Query = Url 中 ‘?’ 后面的 key-value)
如:url = http://www.println.net/?cate=android ,其中,Query = cate
配置时只需要在接口方法中增加一个参数即可:

6.@Path
URL地址的缺省值

7.@Url
直接传入一个请求的 URL变量 用于URL设置

深度详解Retrofit2使用实践

    深度详解Retrofit2使用(一)基础入门 这篇文章主要描述了Retrofit的注解,没有涉及具体Retrofit的使用。今天就以Android为平台,看看Retrofit是如何使用。

一. 准备

  1.1 导入Retrofit库。

上篇文章,我们提到过在Android中如何引入Retrofit库。这里在实际操作下,新建Android项目,在module的build.gradle文件中,添加如下代码,

 

...  
    compile'com.squareup.retrofit2:retrofit:2.0.2'
    compile 'com.squareup.retrofit2:converter-gson:2.0.1'
...

PS: 这里和上篇文章描述不一样,引入了两个依赖,

 

1. compile'com.squareup.retrofit2:retrofit:2.0.2' ,是Retrofit依赖;

2. compile 'com.squareup.retrofit2:converter-gson:2.0.1' 是转换gson的依赖。(默认请求下,Retrofit中的转换对象是RequestBody、ResponseBody,而实际开发中,我们需要其他格式的数据,例如json格式、xml格式,这里我需要转换为json格式,所以就导入这个库)

加入上面的依赖代码后,点击同步,就会去下载他们相关联的依赖库。最后,我们切换到Project模式下,打开External Libraries,可以看到如下的截图,

可以看到,虽然我们只是添加了两个依赖,但是实际上下载了5个库(其他库都是被依赖的),并且这里是自动下载的。这里确实比前面我们在java中手动下载爽啊!

1.2 其他准备

  1. 添加网络权限。因为我们的Android项目需要网络,所以,记得要添加网络权限,

 

...
<uses-permission android:name="android.permission.INTERNET"/>
...

  2. 接口数据

 

因为需要一个服务端提供服务(接口数据),所以,就需要一个服务端。服务端有两种实现方式,

1. 自己搭建服务端,搭建一个简单的服务,具体的搭建可以参考java web开发(二) 接口开发SpringMVC 开发接口;(有的朋友肯定会惊讶,nima,使用Retrofit,还得自己先弄个服务,这代价有点大啊!周期太长了!但是,我想说,如果你对前端和后端都了解的话,那么何愁找不到好工作呢!跑题了,脉动回来)

2. 使用现成的接口,目前市面上第三方提供的接口也较多,可以选择使用。例如,https://api.github.com/

总之,在使用Retrofit前,请先准备好数据接口!

好了,经过上面的步骤,我们就可以开始使用Retrofit了!

二.使用 

    在看这一部分前,建议先看看我之前的一篇文章,java web开发(三) 接口使用

2.1 接口数据

在使用接口数据前,我们先看看数据以及格式是什么样的。

在浏览器中输入接口地址,例如地址是“http://192.168.21.163:8080/mServer/getStudent”,

上面是浏览器的截图,可以看到该json数据的格式是,

 

"code":" ","msg":" ","time":************,"items":[,]  

有关json数据格式在我的java web接口开发系列文章讲到过,这里就不再详细说明了,请看java web开发(二) 接口开发java web开发(三) 接口使用

下面直接给出json数据格式设计。有三个类,

1. Response类 ,所有响应实体的基类,内部有三个字段,code、msg、time。"code”是响应状态码,是标志接口数据的状态;"msg"是响应描述,是对“code”的文字描述;“time”是时间戳。所有的响应实体都应该继承至该类。

2. EntityResponse,继承至Response类,当接口响应数据中只有一个对象时,使用该类,多了一个属性object。

3. ListResponse,继承至Response类,当接口响应数据中返回一个数组时,使用该类,多了一个属性是List。

下面是这几个类的具体实现,

 

**
 *  基类
 */

public class Response implements Serializable 
    private String code;//响应状态码
    private String msg;//响应状态描述
    private Long time = System.currentTimeMillis();//时间戳
    public String getCode() 
        return code;
    

    public void setCode(String code) 
        this.code = code;
    

    public String getMsg() 
        return msg;
    

    public void setMsg(String msg) 
        this.msg = msg;
    

    public Long getTime() 
        return time;
    

    public void setTime(Long time) 
        this.time = time;
    

    @Override
    public String toString() 
        return "Response" +
                "code='" + code + '\\'' +
                ", msg='" + msg + '\\'' +
                ", time=" + time +
                '';
    

/**
 * 单独对象类
 */

public class EntityResponse<T> extends Response 

    private T object;// 返回一个对象的对象

    public T getObject() 
        return object;
    

    public void setObject(T object) 
        this.object = object;
    

    @Override
    public String toString() 
        return "EntityResponse" +
                "object=" + object +
                '';
    

/**
 * 数组实体类
 */

public class ListResponse<T> extends Response 
    private List<T> items;//返回一个数组

    public List<T> getItems() 
        return items;
    

    public void setItems(List<T> items) 
        this.items = items;
    

 下面开始使用Retrofit请求数据。(当点击按钮时,从服务端获取数据,解析后显示)

 

2.2 GET请求

1.接口定义

 

public interface ApiService 

    @GET("StudentInq")
    Call<ListResponse<Student>> getStudents();

  

定义了一个接口,使用GET方式。

 

2.使用

 

...
   public void request() 
        // 1. 创建Retrofit对象
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(Constant.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        // 2. 创建接口对象
        ApiService apiService = retrofit.create(ApiService.class);
        Call<ListResponse<Student>> call = apiService.getStudents();
        call.enqueue(new Callback<ListResponse<Student>>() 
            @Override
            public void onResponse(Call<ListResponse<Student>> call, Response<ListResponse<Student>> response) 
                if(response.isSuccessful())
                   String code= response.body().getCode();
                   String msg= response.body().getMsg();
                    if (code != null
                            && code.equalsIgnoreCase("ok")) 
                        List<Student> list = response.body().getItems();
                        //获取接口返回的列表数据
                        final StringBuffer sb = new StringBuffer();
                        for (Student student : list) 
                            sb.append("姓名:" + student.getName() + ", 年龄" + student.getAge() + ", 电话" + student.getMobile()).append("\\n");
                        
                        //更新UI,在子线程中,不能直接更新UI
                        tv.post(new Runnable() 
                            @Override
                            public void run() 
                                tv.setText(sb.toString());
                            
                        );
                    else
                        Log.e("code---msg-->",code+","+msg);
                    
                else
                    Log.e("response.code()----->",response.code()+"");
                
            

            @Override
            public void onFailure(Call<ListResponse<Student>> call, Throwable t) 

            
        );

...

代码比较简单!完成异步调用,就可以获取到接口数据了。具体代码请看文章末尾的DEMO例子。下面是在手机上的运行截图,

 


上面的例子是一个GET请求。下面再看看POST请求,实际开发中会大量使用POST请求。

2.3 POST请求

1.接口定义

 

public interface ApiService 

    @GET("StudentInq")
    Call<ListResponse<Student>> getStudents();

    @FormUrlEncoded
    @POST("getStudent")
    Call<EntityResponse<Student>> getStudentById(@Field("id") int id);


 

定义POST请求,并且设置了一个参数“id”,通过这个'id'获取某个学生信息。 一定要记得定义POST接口的规范!(使用表单提交POST,一定要@FormUrlEncoded、@Field和@POST配合使用)。

 

2.使用

 

...
    public void request() 
        // 1. 创建Retrofit对象
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(Constant.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        // 2. 创建接口对象
        ApiService apiService = retrofit.create(ApiService.class);
        Call<EntityResponse<Student>> call = apiService.getStudentById(1);

        call.enqueue(new Callback<EntityResponse<Student>>() 
            @Override
            public void onResponse(Call<EntityResponse<Student>> call, Response<EntityResponse<Student>> response) 
                if (response.isSuccessful()) 
                    String code = response.body().getCode();
                    String msg = response.body().getMsg();
                    if (code != null
                            && code.equalsIgnoreCase("ok")) 
                        Student student = response.body().getObject();
                        //获取接口返回的列表数据
                        final String text = "姓名:" + student.getName() + ", 年龄" + student.getAge() + ", 电话" + student.getMobile();
                        //更新UI,在子线程中,不能直接更新UI
                        tv.post(new Runnable() 
                            @Override
                            public void run() 
                                tv.setText(text);
                            
                        );
                     else 
                        Log.e("code---msg-->", code + "," + msg);
                    
                 else 
                    Log.e("response.code()----->", response.code() + "");
                
            

            @Override
            public void onFailure(Call<EntityResponse<Student>> call, Throwable t) 

            
        );
...

上面网络请求的代码和GET请求都是一样的。还是给张运行后的效果截图,

 

  可以看到,使用Retrofit确实很方便、快捷。代码量也很少,效率高!

2.4 补充

1. 使用GET请求从https://api.github.com/获取数据。

 a. 接口定义

 

public interface ApiService 

  
    @GET("/repos/owner/repo/contributors")
    Call<List<Contributor>> contributors(
            @Path("owner") String owner,
            @Path("repo") String repo);

 b. 使用

 

 

   public void request() 
        // 1. 创建Retrofit对象
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(Constant.API_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        // 2. 创建接口对象
        ApiService apiService = retrofit.create(ApiService.class);
        Call<List<Contributor>> call = apiService.contributors("square", "retrofit");
        call.enqueue(new Callback<List<Contributor>>() 
            @Override
            public void onResponse(Call<List<Contributor>> call, Response<List<Contributor>> response) 
                List<Contributor> contributors = response.body();
                //                    //获取接口返回的列表数据
                final StringBuffer sb = new StringBuffer();
                for (Contributor contributor : contributors) 
                    sb.append(contributor.getLogin() + " (" + contributor.getContributions() + ")").append("\\n");;
                
                //更新UI,在子线程中,不能直接更新UI
                tv.post(new Runnable() 
                    @Override
                    public void run() 
                        tv.setText(sb.toString());
                    
                );
            

            @Override
            public void onFailure(Call<List<Contributor>> call, Throwable t) 

            
        );

    

看效果,

 

其实这个实例是Retrofit的github中的例子。
2. Retrofit结合Rxjava

  使用Rxjava前,需要先导入其依赖。

 

...
    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
    compile 'io.reactivex.rxjava2:rxjava:2.1.5'
    compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
...

compile 'io.reactivex.rxjava2:rxjava:2.0.1'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1' ,使用Rxjava,需要引入两个依赖库

 

compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0' ,衔接 Retrofit & RxJava

加入这几行代码后,点击同步,稍等就可以了!

a. 接口定义

 

...
    @GET("StudentInq")
    Observable<ListResponse<Student>> getStudents();
...

 

只是将方法返回值类型更改了。之前是Call,现在是Observable(被观察者)。

b. 请求

 

...

    public void request() 
        // 1. 创建Retrofit对象
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(Constant.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 支持RxJava
                .build();
        // 2. 创建接口对象
        ApiService apiService = retrofit.create(ApiService.class);
        Observable<ListResponse<Student>> call = apiService.getStudents();
        call.subscribeOn(Schedulers.io()) // 在IO线程进行网络请求
                .observeOn(AndroidSchedulers.mainThread()) // 回到主线程 处理请求结果
                .subscribe(new Consumer<ListResponse<Student>>() 
            @Override
            public void accept(ListResponse<Student> studentListResponse) throws Exception 
                List<Student> list = studentListResponse.getItems();
                //获取接口返回的列表数据
                final StringBuffer sb = new StringBuffer();
                for (Student student : list) 
                    sb.append("姓名:" + student.getName() + ", 年龄" + student.getAge() + ", 电话" + student.getMobile()).append("\\n");
                
                tv.setText(sb.toString());
            
        );

...

运行效果就不截图了!比较下来,Retrofit和Rxjava配合使用更加方便、高效!如虎添翼!
三.小结

 

  本文只是简单的使用了几个Retrofit的注解,其他很多注解都没有讲解。GET和POST,这两种请求是比较常用的,尤其是POST在网络交互中大量使用,如果你对本文中的例子理解了,那么就足够了;至于其他的注解,在你需要使用的时候,即时查阅资料会使用就可以了。本文也简单使用了Rxjava,相信大家也看到了Rxjava的强大,如果还未了解Rxjava,就赶紧动手吧!

 1.  可以看到,不管是GET请求还是POST请求,仅仅是在定义接口的地方不一样,真正网络请求的地方,代码都是一样的。

 2.  Retrofit和OkHttp有什么区别呢?

    我们都知道OkHttp是目前使用频率最多的网络请求库,它的功能相当强大,它是Square公司的开源库。而Retrofit呢,它也是Square公司的开源库,并且Retrofit的网络请求其实是由OkHttp完成的。虽然Retrofit的网络请求是OkHttp完成的,但是,我们在使用Retrofit的时候,根本就察觉不到;如果我们将之前的网络请求由OkHttp改为Retrofit,也是很easy的。Retrofit是对OkHttp的封装,让使用者更方便、快捷的实现网络请求。赶紧入手Retrofit吧!

  前面一直提到过,Retrofit是对OkHttp的封装,那么我们可以替换调默认的OkHttp吗?相信聪明的你肯定已经猜到答案了!

  客户端Demo下载地址

欢迎大家关注我的公众号

 



 

 

 

 

 

 

 


 

 

 

 

以上是关于Android Retrofit详解的主要内容,如果未能解决你的问题,请参考以下文章

RxJava 与 Retrofit 结合的最佳实践

Android Retrofit详解

Android Retrofit详解

Android 网络框架之Retrofit2使用详解及从源码中解析原理

深度详解Retrofit2使用实践

深度详解Retrofit2使用实践