天天看点

每天学习一个Android中的常用框架——5.Retrofit

文章目录

  • ​​1.简介​​
  • ​​2.特性​​
  • ​​3.演示​​
  • ​​3.1 集成​​
  • ​​3.2 配置​​
  • ​​3.3 布局文件和URL封装​​
  • ​​3.5 GET请求——传统网络参数​​
  • ​​3.6 GET请求——RestFul风格​​
  • ​​3.7 POST请求​​
  • ​​4.源码地址​​

1.简介

在介绍Android中相关网络框架的时候,我们介绍过了Square公司制作的OkHttp和OKIo。事实上,这两个框架配合使用的时候,基本上已经可以完成大部分的网络业务需求了。不过,学习是永远没有尽头的。这篇博客中,我们将介绍同样由Square公司制作,目前同样流行的另一个网络框架——Retrofit

Retrofit是一个现在比较火的网络请求框架,它的底层是依靠OkHttp实现的。确切的讲,Retrofit是对OkHttp的进一步封装,它的功能更加强大,支持同步和异步、支持多种数据的解析(默认使用Gson),也支持RxJava。

Retrofit的一个优势,就是简洁易用,它通过注解配置网络请求的参数,采用大量的设计模式来简化我们的使用。而且它的拓展性也做的相当的好,Retrofit的功能模块高度封装,高内聚低耦合,我们可以自定义自己想要的组件,比如说我们可以自己选择解析工具而不用默认的Gson,实现了高度的定制性。

除此之外,Retrofit还有诸如性能好,处理速度快,代码简化等优势,给足了理由让我们去尝试使用这款网络请求框架。

2.特性

在使用Retrofit之前,我们应该先了解它的特性。使用Retrofit的过程中,由于其大量注解开发的形式,我觉得十分类似于Java中的Spring MVC框架,通过标识专属的注解,就可以达到快速的配置和开发,一些Retrofit常见的方法注解如图所示:

每天学习一个Android中的常用框架——5.Retrofit

除此之外,一些常见的字段注解如图所示:

每天学习一个Android中的常用框架——5.Retrofit

将这些注解进行整理,可以得到一张大致的结构图:

其中:

  1. 网络请求方法
  2. 每天学习一个Android中的常用框架——5.Retrofit
  3. 标记类
  4. 每天学习一个Android中的常用框架——5.Retrofit
  5. 网络请求参数
  6. 每天学习一个Android中的常用框架——5.Retrofit

看到这么多的注解,是否有一种头晕目眩的感觉?没关系,在本篇博客中,只会演示比较常用的注解:​

​@GET,@POST,@Path,@Query​

​​ ,其他的代码可以根据需求进行相应地调用,调用过程是类似的,具体的api调用还是那句话:查看​​Retrofit官网​​获取更多的相关信息。

3.演示

3.1 集成

在使用任何框架之前,集成都是第一步。由于Retrofit已经用到了OkHttp,所以这里只需要导入Retrofit一个依赖即可,修改module下的build.gradle,代码如下:

implementation 'com.squareup.retrofit2:retrofit:2.8.1'      

修改完成后Sync一下,确保Retrofit集成到了你的项目中。

3.2 配置

这里的配置主要是针对在使用Retrofit遇到的一个坑,简单提一下避免读者在使用的时候踩坑。

问题:导入Retrofit依赖后,在build工程后出现如图所示的错误

每天学习一个Android中的常用框架——5.Retrofit
每天学习一个Android中的常用框架——5.Retrofit

原因:从出错原因可以很简单地看出,使用Retrofit需要你的Android版本最低达到Android O(即api 26),所以只需要修改有关此处的配置信息即可。

解决方法:在项目下的build.gradle文件添加一个​

​compileOptions​

​闭包,声明JDK版本,代码如下:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.3"

    defaultConfig {
        applicationId "com.androidframelearn.http_retrofit"
        minSdkVersion 16
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    implementation 'com.squareup.retrofit2:retrofit:2.8.1'

    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}      

3.3 布局文件和URL封装

接下来,我们直接开始布局文件activity_main.xml的编写。该布局很简单,仅有四个按钮,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <Button
        android:id="@+id/btn_get"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="发送get请求——通过http拼接网络参数"/>

    <Button
        android:id="@+id/btn_get_restful"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="发送get请求——通过restful拼接网络参数"/>

    <Button
        android:id="@+id/btn_post"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="发送post请求"/>


</LinearLayout>      

之后,我们简单用字符串封装一下要请求的URL。这里封装两个URL,是为了演示分别通过传统方式和RestFul风格提交GET请求的不同效果(现在很少有RestFul风格的免费开放api,所以这里就只能假设一个本地的Tomcat服务器,然后放置一个JSON文件来进行校验),代码如下(服务器URL不固定,根据自己的服务器路径名进行相应修改):

private static final String URL = "https://tcc.taobao.com/cc/json/";

    private static final String LOCALURL = "http://10.0.2.2:8080/";      

这里的​

​URL​

​​是一个目前还开放的可以查看电话归属地信息的api,而​

​LOCALURL​

​则是本地服务器的api。

另外:保证你的URL路径输入到网页的链接栏中是可以访问的!这点很重要,如果你输入的网页是不存在的(即body为null),那么在调用​

​response.body().string()​

​时就会报出空指针的异常,如图所示:

每天学习一个Android中的常用框架——5.Retrofit

3.5 GET请求——传统网络参数

编写一个名为TestService的接口,其中有一个名为getInfoByHttp的方法,代码如下:

public interface TestService {
/**
     /**
     * 通过拼接网络参数的方式提交GET请求(下面的参数为https://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=15878896543)
     * 注意:这种方式为http的参数传递方式,若使用这种方式请求,需要在注解上使用@Query而非@Path
     * @param tel
     * @return
     */
    @GET("mobile_tel_segment.htm")
    Call<ResponseBody> getInfoByHttp(@Query("tel") String tel);
}      

我们定义了一个getInfoByHttp方法,其返回类型为retrofit的Call类型,尖括号里是okhttp的ResponseBody类型,​

​@GET​

​​注解的作用是声明采用GET的方法进行网络请求,而​

​@Query​

​​注解的作用是声明其之后的​

​String tel​

​​参数,将以路径的形式被拼接到​

​@GET​

​​注解括号里的​

​{mobile_tel_segment.htm}​

​​处。比如说,之后我们在调用getInfoByHttp方法时传入参数​

​15878896543​

​​,​

​@GET​

​​注解里将会被转化为 ​

​mobile_tel_segment.htm?tel=15878896543​

​​,这个​

​15878896543​

​​又会被接到我们之前设置的​

​baseUrl​

​​之后,变成 ​

​https://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=15878896543​

​,这样就变成了一个完整的网络请求地址。

其实使用Retrofit进行GET请求有点类似于OkHttp,步骤可以大抵分为:

  • 通过建造者模式创建Retrofit对象
  • 通过Retrofit对象的​

    ​create()​

    ​方法来获取服务接口的实例
  • 通过接口服务的实例来创建Call对象
  • 通过Call对象的​

    ​enqueue()​

    ​异步提交请求
  • 通过​

    ​response.body().string()​

    ​获取请求信息

代码如下:

private void getByRetrogit() {
        btn_get.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 1.使用建造者模式创建Retrofit实例
                Retrofit retrofit = new Retrofit.Builder()
                        .baseUrl(URL)
                        .build();
                // 2.使用Retrofit对象调用create()创建服务实例(BookService)
                TestService testService = retrofit.create(TestService.class);
                // 3.通过服务实例创建Call对象
                Call<ResponseBody> call = testService.getInfoByHttp("15878896543");
                // 4.通过Call对象构建网络请求(异步)
                call.enqueue(new Callback<ResponseBody>() {
                    @Override
                    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                        try {
                            String output = response.body().string();
                            Log.i(TAG,"GET请求发送成功!获取到的信息为:" + output);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    @Override
                    public void onFailure(Call<ResponseBody> call, Throwable t) {
                        Log.i(TAG,"GET请求发送失败");
                    }
                });
            }
        });
    }      

测试效果如图所示:

每天学习一个Android中的常用框架——5.Retrofit

3.6 GET请求——RestFul风格

编写一个名为TestService的接口,其中有一个名为getInfoByRestFul的方法,代码如下:

public interface TestService {
/**
     * 通过restful的方式提交GET请求(下面的参数为http://10.0.2.2:8080/update74.json)
     * @param filename
     * @return
     */
    @GET("{filename}")
    Call<ResponseBody> getInfoByRestFul(@Path("filename") String filename);
}      

我们定义了一个getInfoByRestFul方法,其返回类型为retrofit的Call类型,尖括号里是okhttp的ResponseBody类型,​

​@GET​

​​注解的作用是声明采用GET的方法进行网络请求,而​

​@Path​

​​注解的作用是声明其之后的​

​String filename​

​​参数,将以路径的形式被替换到​

​@GET​

​​注解括号里的​

​{filename}​

​​处。比如说,之后我们在调用getInfoByRestFul方法时传入参数​

​update74.json​

​​,​

​@GET​

​​注解里将会被转化为 ​

​update74.json​

​​,这个​

​update74.json​

​​又会被接到我们之前设置的​

​baseUrl​

​​之后,变成 ​

​http://10.0.2.2:8080/update74.json​

​,这样就变成了一个完整的网络请求地址。

其实使用Retrofit进行GET请求有点类似于OkHttp,步骤可以大抵分为:

  • 通过建造者模式创建Retrofit对象
  • 通过Retrofit对象的​

    ​create()​

    ​方法来获取服务接口的实例
  • 通过接口服务的实例来创建Call对象
  • 通过Call对象的​

    ​enqueue()​

    ​异步提交请求
  • 通过​

    ​response.body().string()​

    ​获取请求信息

代码如下:

private void getByRetrogitForRestful() {
        btn_get_restful.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 1.使用建造者模式创建Retrofit实例
                Retrofit retrofit = new Retrofit.Builder()
                        .baseUrl(LOCALURL)
                        .build();
                // 2.使用Retrofit对象调用create()创建服务实例(BookService)
                TestService testService = retrofit.create(TestService.class);
                // 3.通过服务实例创建Call对象
                Call<ResponseBody> call = testService.getInfoByRestFul("update74.json");
                // 4.通过Call对象构建网络请求(异步)
                call.enqueue(new Callback<ResponseBody>() {
                    @Override
                    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                        try {
                            String output = response.body().string();
                            Log.i(TAG,"GET请求发送成功!获取到的信息为:" + output);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    @Override
                    public void onFailure(Call<ResponseBody> call, Throwable t) {
                        Log.i(TAG,"GET请求发送失败");
                    }
                });
            }
        });
    }      

测试效果如图所示:

每天学习一个Android中的常用框架——5.Retrofit

3.7 POST请求

编写一个名为TestService的接口,其中有一个名为postInfoByRestFul的方法,代码如下:

public interface TestService {
/**
     * 通过restful的方式提交POST请求(下面的参数为http://10.0.2.2:8080/update74.json)
     * @param filename
     * @return
     */
    @POST("{filename}")
    Call<ResponseBody> postInfoByRestFul(@Path("filename") String filename);
}      

事实上,发送POST请求与GET请求的区别就是注解,需要使用​

​@POST​

​。其他的调用方式跟上面是一样的,创建POST请求提交的步骤也是跟GET请求也一样,所以这里就不再赘述了,直接贴上代码:

private void postByRetrogit() {
        btn_post.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 1.使用建造者模式创建Retrofit实例
                Retrofit retrofit = new Retrofit.Builder()
                        .baseUrl(LOCALURL)
                        .build();
                // 2.使用Retrofit对象调用create()创建服务实例(BookService)
                TestService testService = retrofit.create(TestService.class);
                // 3.通过服务实例创建Call对象
                Call<ResponseBody> call = testService.postInfoByRestFul("update74.json");
                // 4.通过Call对象构建网络请求(异步)
                call.enqueue(new Callback<ResponseBody>() {
                    @Override
                    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                        try {
                            String output = response.body().string();
                            Log.i(TAG,"POST请求发送成功!获取到的信息为:" + output);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    @Override
                    public void onFailure(Call<ResponseBody> call, Throwable t) {
                        Log.i(TAG,"POST请求发送失败");
                    }
                });
            }
        });
    }      

测试效果如图所示:

4.源码地址