【Android】Retrofit使用详解--有些相见恨晚

1.Retrofit介绍

Retrofit,每次浏览各大网站总会看到它的身影,虽然感觉已经如此熟悉,但是确实又相当陌生,由于一直没有在项目中使用它,今天决定好好整理下,虽然Retrofit1.0的时代已经过去,还好赶上了retrofit2.0的脚步,据说它又更强大了,废话不多说了,让我们去揭开Retrofit的神秘面纱;

  • A type-safe HTTP client for Android and Java
    一个用于Android和Java平台的类型安全的网络框架

  • Retrofit is a type-safe REST client for Android built by Square. The library provides a powerful framework for authenticating and interacting with APIs and sending network requests with OkHttp.

  • Retrofit 是一个Square开发的类型安全的REST安卓客户端请求库。这个库为网络认证、API请求以及用OkHttp发送网络请求提供了强大的框架 。

  • Retrofit 2 现在开始依赖了 OkHttp 了,而且这部分不再支持替换。这是一件比较有争议的事情。但是希望我能证明为什么这是一个对的决定。OkHttp 现在很小而且很聚焦,有很多好用的 API 接口。我们在 Retrofit 2 里都有对 OkHttp 的接口映射,也基本具备了我们需要的所有的特性,包括提到的所有的抽象类们。这些都超赞!这是压缩 Retrofit 库大小的一个法宝。我们最终减小了Retrofit 60% 的体积,同时又具有了更多的特性。—–来自用 Retrofit 2 简化 HTTP 请求

2.Retrofit配置

如果你使用的Android Studio 请配置Gradle文件 :

compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'

Maven :

<dependency>
  <groupId>com.squareup.retrofit</groupId>
  <artifactId>retrofit</artifactId>
  <version>2.0.0-beta2</version>
</dependency>

3.get请求

此处我使用了百度apistore上的一个查询身份证信息的接口来演示一下get请求方式。

首先搞个实体类CardModel:

public class CardModel
{
    /**
     * errNum : 0
     * retMsg : success
     * retData : {"address":"湖北省孝感市汉川市","sex":"M","birthday":"1987-04-20"}
     */

    private int errNum;
    private String retMsg;
    /**
     * address : 湖北省孝感市汉川市
     * sex : M
     * birthday : 1987-04-20
     */

    private RetDataBean retData;

    public int getErrNum()
    {
        return errNum;
    }

    public void setErrNum(int errNum)
    {
        this.errNum = errNum;
    }

    public String getRetMsg()
    {
        return retMsg;
    }

    public void setRetMsg(String retMsg)
    {
        this.retMsg = retMsg;
    }

    public RetDataBean getRetData()
    {
        return retData;
    }

    public void setRetData(RetDataBean retData)
    {
        this.retData = retData;
    }

    public static class RetDataBean
    {
        private String address;
        private String sex;
        private String birthday;

        public String getAddress()
        {
            return address;
        }

        public void setAddress(String address)
        {
            this.address = address;
        }

        public String getSex()
        {
            return sex;
        }

        public void setSex(String sex)
        {
            this.sex = sex;
        }

        public String getBirthday()
        {
            return birthday;
        }

        public void setBirthday(String birthday)
        {
            this.birthday = birthday;
        }
    }
}

① 通过注解声明参数信息

public interface PhoneApiService
{
    //get请求方式
    @GET("/apistore/idservice/id")
    public Call<CardModel> getCardGetState(
        //动态添加请求header
        @Header("apikey") String apikey,
        //请求参数,形如?id=XXXX
        @Query("id") String id);
}

② 创建Retrofit实例:

Retrofit retrofit = new Retrofit.Builder()
                //baseurl表示服务器的主机地址
                .baseUrl(“http://apis.baidu.com”)
                //指定解析方式,此处使用gson解析,请求后直接返回实体对象
                .addConverterFactory(GsonConverterFactory.create())
                .build();

③ 通过Service获取call对象:

PhoneApiService pApiService = retrofit.create(PhoneApiService.class);

        Call<CardModel> call = pApiService.getCardGetState("9c32fd04cda3a80c3cff414c7e50e2f5","430224198508085219");

④ 发送异步请求:

call.enqueue(new Callback<CardModel>()
        {

            @Override
            public void onResponse(Call<CardModel> arg0, Response<CardModel> response)
            {
                CardModel model = response.body();
                tvShow.setText("post地址:"+model.getRetData().getAddress());
                Toast.makeText(MainActivity.this, ""+model.toString(), Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onFailure(Call<CardModel> arg0, Throwable arg1)
            {
                Log.e("error",""+arg1.toString());
                Toast.makeText(MainActivity.this, ""+arg1.toString(), Toast.LENGTH_SHORT).show();
            }
        });

最后请求的时候,请求地址会拼接成:http://apis.baidu.com/apistore/idservice/id?id=430224198508085219的格式;我们发送请求后会通过response.body()即可获得我们的CardModel对象:

这里写图片描述

上面是一个请求参数的情况,如果你有多个请求参数,retrofit提供了@QueryMap注解,我们可以传递一个map对象,用键值对的方式来添加请求参数:

@GET("/apistore/idservice/id")
    public Call<CardModel> getCardGetState(
        @Header("apikey") String apikey,
        //请求参数,形如?id=XXXX
        @QueryMap Map<String, String> map);

那么问题又来了,如果我们要添加多个header呢,同样可以通过@HeaderMap注解来添加多个header:

@GET("/apistore/idservice/id")
Call<CardModel> getCardGetState(@HeaderMap Map<String, String> headerMap)

我们还可以通过@Headers注解来添加静态的header,形如:

@Headers({
    "Accept: application/vnd.github.v3.full+json",
    "User-Agent: Retrofit-Sample-App"
})
@GET("/apistore/idservice/id")
    public Call<CardModel> getCardGetState(
         @QueryMap Map<String, String> map);

4.post请求

post请求我就用一个我司一个小项目的登录接口来演示一下;

请求成功返回的json如下(有一部分省略),实体类就不贴了:

{
    "code": 0,
    "data": {
        "mediatorId": 1236,
        "rsMediationCaseList": null,
        "rsOrganization": null,
        "orgName": null,
        "orgId": null,
        "name": "张三",
        "sex": null,
        "job": null,
        "mediatorIdentity": "相见恨晚啊",
        "culturalLevel": null,
        "birthday": null,
        "birthdayStr": null,
        "idCardNumber": null,
        "areaCode": null,
        "areaName": null,
        "address": null  
    }
}

① 通过注解声明参数信息

@POST("/app/mediator/login")
    Call<RSMediator> loginPost(@Body UserModel user
    );

此处出现了@Body注解,通过@Body注解可以声明一个对象作为请求体发送到服务器,我这里生命了一个UserModel 对象来作为请求体,代码和普通的实体类一样:

public class UserModel
{
    //手机号
    String telephone;
    //登录密码
    String userPwd;

    public UserModel()
    {
    }

    public UserModel(String telephone, String userPwd)
    {
        this.telephone = telephone;
        this.userPwd = userPwd;
    }

    public String getTelephone()
    {
        return telephone;
    }

    public void setTelephone(String telephone)
    {
        this.telephone = telephone;
    }

    public String getUserPwd()
    {
        return userPwd;
    }

    public void setUserPwd(String userPwd)
    {
        this.userPwd = userPwd;
    }
}

② 创建Retrofit实例:

//和Get一样,没变化
Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(“http://192.168.60.224:8080”)
                .addConverterFactory(GsonConverterFactory.create())
                .build();

③ 通过Service获取call对象:

PhoneApiService pApiService = retrofit.create(PhoneApiService.class);
//创建请求体
UserModel user = new UserModel("13801595313","123456");
Call<RSMediator> call = pApiService.loginPost(user);

④ 发送异步请求:

call.enqueue(new Callback<RSMediator>()
        {
            @Override
            public void onResponse(Call<RSMediator> call, Response<RSMediator> response)
            {
                RSMediator mediator = response.body();
                tvShow.setText(mediator.toString());
                Toast.makeText(MainActivity.this, ""+mediator.toString(), Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onFailure(Call<RSMediator> call, Throwable t)
            {
                tvShow.setText(t.toString());
            }
        });

运行结果如下:

这里写图片描述

post还支持表单提交,形如:

@FormUrlEncoded
@POST("/some/endpoint")
Call<SomeResponse> someEndpoint(
    @Field("telephone") String telephone,
    @Field("pwd") String pwd);

另外,我们可以使用@Url 主句,允许你直接传入一个请求的 URL。

@GET
Call<List<Contributor>> repoContributorsPaginate(
      @Url String url);
//获取到新的url
String nextLink = nextFromGitHubLinks(links);
//直接传如url即可
Call<List<Contributor>> nextCall =
    gitHubService.repoContributorsPaginate(nextLink);

我们就用文章上面的get请求的路径来测试一下@URL注解,http://apis.baidu.com/apistore/idservice/id?id=430224198508085219

@Headers("apikey:9c32fd04cda3a80c3cff414c7e50e2f5")
@GET
Call<CardModel> loadUrl(@Url String url);

调用的时候传入完整的url路径:

Call<CardModel> call = pApiService.loadUrl("http://apis.baidu.com/apistore/idservice/id?id=430224198508085219");

这里写图片描述

5.log拦截器

开发中,Debug模式希望可以看到log,网络请求,打印Log信息,发布的时候就不需要这些log

在build.gradle中添加依赖:

compile 'com.squareup.okhttp3:logging-interceptor:3.1.2'

在构建okhttpclient对象的时候,通过addInterceptor添加拦截器:

//关键代码
if (BuildConfig.DEBUG) {
    // Log信息拦截器
    HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
    loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
    //设置 Debug Log 模式
    builder.addInterceptor(loggingInterceptor);
}

然后我们在接收网络请求的时候就会打印日志信息:

这里写图片描述

6.统一设置请求头

通过拦截器统一设置请求头:

Interceptor headerInterceptor = new Interceptor() {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request originalRequest = chain.request();
        Request.Builder requestBuilder = originalRequest.newBuilder()
                .header("Content-Type", "application/json")
                .header("Accept", "application/json")
                .method(originalRequest.method(), originalRequest.body());
        Request request = requestBuilder.build();
        return chain.proceed(request);
    }
};
//设置头
builder.addInterceptor(headerInterceptor);

7.设置超时和重连

在构建OKHttpClient对象的时候,build之前进行设置,最后构建Retrofit的时候client(okHttpClient)传入即可:

//设置超时
builder.connectTimeout(15, TimeUnit.SECONDS);
builder.readTimeout(20, TimeUnit.SECONDS);
builder.writeTimeout(20, TimeUnit.SECONDS);
//错误重连
builder.retryOnConnectionFailure(true);

8.介绍一下容易混淆的几个注解

刚开始学习Retrofit的时候,对@Path,@Query,@Field几个注解有些模糊,现在梳理一下:

@GET("2016/{article}/retrofit")
Call<ResponseBody> getData(@Path("article") String article);

即传的参数article内容会替换大括号里的内容。

@GET("article")
Call<ResponseBody> getData(@Query("id") String id);

@Query修饰的参数会拼接在url的后面,形如?id=’id’。

  • Field:表单提交,如登录
@FormUrlEncoded
@POST("v1/login")
Call<ResponseBody> userLogin(@Field("phone") String phone, @Field("password") String password);

@Field,post提交时,用@Field来修饰参数。

9.混淆

-dontnote retrofit2.Platform
-dontnote retrofit2.Platform$IOS$MainThreadExecutor
-dontwarn retrofit2.Platform$Java8
-keepattributes Signature
-keepattributes Exceptions

至此,本篇文章就先介绍这么多,当然还有一些没有介绍的知识点将在后续博文中陆续介绍,欢迎各位交流学习;

参考链接:

1.用 Retrofit 2 简化 HTTP 请求

2.Android Retrofit 2.0 使用-补充篇

3.Retrofit项目封装使用

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值