Retrofit是Square公司发布的一个可以应用在Android和Java中的Http客户端访问框架,其底层应用的是OkHttp。

  在这个帖子中,我们以下面这个Http请求为例:

https://api.github.com/users/basil2style

  其请求结果(JSON)如下所示:

{
"login": "basil2style",
"id": 1285344,
"avatar_url": "https://avatars.githubusercontent.com/u/1285344?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/basil2style",
"html_url": "https://github.com/basil2style",
"followers_url": "https://api.github.com/users/basil2style/followers",
"following_url": "https://api.github.com/users/basil2style/following{/other_user}",
"gists_url": "https://api.github.com/users/basil2style/gists{/gist_id}",
"starred_url": "https://api.github.com/users/basil2style/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/basil2style/subscriptions",
"organizations_url": "https://api.github.com/users/basil2style/orgs",
"repos_url": "https://api.github.com/users/basil2style/repos",
"events_url": "https://api.github.com/users/basil2style/events{/privacy}",
"received_events_url": "https://api.github.com/users/basil2style/received_events",
"type": "User",
"site_admin": false,
"name": "Basil",
"company": "MakeInfo",
"blog": "http://www.themakeinfo.com",
"location": "Toronto,Canada",
"email": "basiltalias92@gmail.com",
"hireable": true,
"bio": "Developer | Marketer | Reader | Cinephile | Entrepreneur",
"public_repos": 35,
"public_gists": 4,
"followers": 64,
"following": 155,
"created_at": "2011-12-26T00:17:22Z",
"updated_at": "2016-11-12T00:58:15Z"
}

  接下来我们从Retrofit的用法到原理,来介绍一下这个框架。

一、Retrofit的用法:

0、配置Retrofit的开发环境:

  我们在使用Retrofit之前需要先导入Retrofit的包,本DEMO是在Android Studio中开发的,因此只需要在gradle文件中导入依赖即可。下面是Retrofit的依赖:

compile 'com.squareup.retrofit2:retrofit:2.1.0'

  另外,我们从网络中获取到的数据的格式是不同的,可能是JSON/GSON格式,也可能是Jackson、Wire等其他格式,我们需要在后面的编码中用到一个格式转化工厂ConverterFactory,因此我们还需要导入一些有关格式的依赖。本DEMO中使用的是JSON/GSON格式,因此导入相关依赖如下:

compile 'com.squareup.retrofit2:converter-gson:2.1.0'

  其他格式需要导入的依赖列表如下(后面的版本号自己添加):

    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 XML: com.squareup.retrofit2:converter-simplexml
Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars 

  至此,Retrofit的开发环境搭建就完成了。

1、创建一个从网络中获取数据的Service接口:

  Retrofit使用动态代理的方式,将一个网络请求转换成一个接口,用户只需要调用一个接口就可以进行网络访问。这个接口的代码如下:

public interface RetrofitService {
@GET("/users/basil2style")
Call<InfoData> getInfoData();
}

  从上面这段代码中可以看出来, @GET 标签中的值只是这个请求的一部分。一般我们在进行网络请求的时候,大多数请求都是从一个服务器发送的数据,因此我们可以对这些请求的根URL进行统一的管理。在这个DEMO中,我把网络请求的根URL放在SharedData类中:

public class SharedData {
/**
* Base Url
*/
public static final String BASE_URL = "https://api.github.com";
}

  和其他网络请求相同,Retrofit可以通过 @GET 和 @POST 两种方法进行网络请求,这些请求有时候需要携带参数,有时候不需要,上面的getInfoData()方法就是一个不携带任何参数的网络请求方法。当然,这里还需要创建一个Bean类InfoData,用来存储从网络中获取到的数据:

public class InfoData {
private String login;
private int id;
private String avatarUrl;
private String gravatarId;
private String url;
private String htmlUrl;
private String followersUrl;
private String followingUrl;
private String gistsUrl;
private String starredUrl;
private String subscriptionsUrl;
private String organizationsUrl;
private String reposUrl;
private String eventsUrl;
private String receivedEventsUrl;
private String type;
private boolean siteAdmin;
private String name;
private String company;
private String blog;
private String location;
private String email;
private boolean hireable;
private String bio;
private int publicRepos;
private int publicGists;
private int followers;
private int following;
private String createdAt;
private String updatedAt; // Getter、Setter方法
}

  再来介绍一下Call。Call可以用来发送一个请求,Call对象中有两个方法:enqueue()和execute(),前者用来发送一个异步请求,后者又来发送一个同步请求,下面会有代码介绍。

2、初始化Retrofit对象:

  创建Retrofit对象的代码如下:

        Retrofit retrofit = new Retrofit.Builder()
.baseUrl(SharedData.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();

  可以看到,Retrofit对象是通过Retrofit.Builder内部类创建出来的,baseUrl是需要访问的根URL;由于请求的数据是JSON格式的,我们可以使用一个和JSON有关的转换工厂来处理这些数据,这里用到的是和JSON差不多的GSON转化工厂,即GsonConverterFactory。

3、调用Retrofit对象进行网络访问:

  获取到Retrofit对象后,我们通过这个对象获取到网络请求接口RetrofitService,再调用其中的getInfoData()方法获取到网络数据即可。具体代码如下:

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

        Call<InfoData> call = service.getInfoData();
call.enqueue(new Callback<InfoData>() {
@Override
public void onResponse(Call<InfoData> call, Response<InfoData> response) {
InfoData data = response.body();
Message message = Message.obtain();
message.what = 1;
message.obj = data;
handler.sendMessage(message);
} @Override
public void onFailure(Call<InfoData> call, Throwable t) {
handler.sendEmptyMessage(0);
}
});

  这里还需要说明一下,Retrofit不像Volley可以直接把异步数据拉回到主线程,Retrofit中Callback类的onResponse()方法仍然是在异步线程中的,如果我们要将数据拿到主线程,需要使用AsyncTask或Handler,本DEMO中使用的是Handler,以下是Handler中的代码:

    private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
InfoData data = (InfoData) msg.obj;
Toast.makeText(MainActivity.this, data.getBlog(), Toast.LENGTH_SHORT).show();
break;
case 0:
Toast.makeText(MainActivity.this, "获取数据失败", Toast.LENGTH_SHORT).show();
break;
}
}
};

  到此为止Retrofit访问网络获取数据的DEMO就完成了,运行结果如下图所示:

二、RetrofitService接口方法种类:

  上面的RetrofitService接口中的getInfoData()方法只是一个没有携带任何参数的GET请求,我们在访问网络数据的时候有时需要使用POST请求,并且可能会携带一些参数等,下面来逐个介绍一下这些情况下接口方法的编写方式。

  特别说明:下面访问的接口和上面DEMO中的接口没有任何关系,两两之间也没有任何关系!

1、没有参数的GET请求:

    @GET("users/list")
Call<List<User>> getUserList();

2、有参数的GET请求:

(1)第一种方式:在GET标签中添加参数:

    @GET("users/list?sort=desc")
Call<List<User>> getUserList();

(2)第二种方式:在方法参数中设置参数:

    @GET("users/list")
Call<List<User>> getUserList(@Query("sort") String sort); 

3、在GET标签中设置路径参数:

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

4、传入参数列表:

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

5、POST方式请求:

    @POST("users/new")
Call<User> createUser(@Body User user);

三、Retrofit原理:

  Retrofit用注解来描述一个网络请求,将一个网络请求抽象成一个接口,然后使用Java动态代理的方式动态的将这个接口“翻译”成一个网络请求,最后调用OkHttp去执行这个请求。

  Retrofit中的动态代理主要体现在下面这行代码:

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

  create()方法的源码如下:

/** Create an implementation of the API defined by the {@code service} interface. */
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() {
private final Platform platform = Platform.get(); public Object invoke(Object proxy, Method method, Object... args) throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}

  可见,所谓的动态代理,就是给程序员一种可能:在执行某个操作(如打开某个Class)之前,插入一段你想要执行的代码。比如你在执行某个操作之前判断用户是否已经登录,等。

  当外界(Activity)通过create()方法打开这个接口并调用其中的方法时,底层就调用了上面这段代码中的invode()方法。这个方法是通过Java反射机制获取到接口中的getInfoData()方法,用这个方法作为参数创建一个ServiceMethod对象,最后使用OkHttp的API调用进行网络访问。

  总结一下:Retrofit使用注解的方式将一个网络请求封装成一个接口,然后使用动态代理的方法,在插入的代码中通过反射机制找到接口中的方法,封装到OkHttp中进行网络访问,最后对网络访问得到的Call对象进行enqueue()或execute()操作,在回调的方法中处理网络获取到的数据。

  以上就是Retrofit的工作原理。

【Android - 框架】之Retrofit的使用的更多相关文章

  1. 【Android - 框架】之Retrofit+RxJava的使用

    前几天分别对Retrofit和RxJava进行了总结,这个帖子打算把Retrofit结合RxJava使用的方法总结以下.有还不了解Retrofit或RxJava的朋友可以参考下面的帖子学习~ [And ...

  2. App 组件化/模块化之路——Android 框架组件(Android Architecture Components)使用指南

    面对越来越复杂的 App 需求,Google 官方发布了Android 框架组件库(Android Architecture Components ).为开发者更好的开发 App 提供了非常好的样本. ...

  3. Android 框架简介--Java环境(转)

    ==========================上=========================== 这里简单的介绍了Android的java环境基础,在后面一节中会结合具体的实例来理解这一节 ...

  4. 【Android - 框架】之GreenDao的使用

    上一篇博客([Android - 框架]之ORMLite的使用)中介绍了ORMLite的基本使用,今天我们来研究以下GreenDao的使用. GreenDao和ORMLite一样,都是基于ORM(Ob ...

  5. IOS 与ANDROID框架及应用开发模式对照一

    IOS 和ANDROID操作系统都是眼下流行的移动操作系统,被移动终端和智能设备大量採用,两者都採用了先进的软件技术进行设计,为了方便应用开发两者都採用了先进的设计模式. 两者在框架设计上都採用了什么 ...

  6. Kotlin的扩展函数:扩展Android框架(KAD 08)

    作者:Antonio Leiva 时间:Jan 11, 2017 原文链接:https://antonioleiva.com/extension-functions-kotlin/ 扩展函数是Kotl ...

  7. 【Android 系统开发】Android框架 与 源码结构

    一. Android 框架 Android框架层级 : Android 自下 而 上 分为 4层; -- Linux内核层; -- 各种库 和 Android运行环境层; -- 应用框架层; -- 应 ...

  8. IOS 与ANDROID框架及应用开发模式对比一

    IOS 和ANDROID操作系统都是目前流行的移动操作系统,被移动终端和智能设备大量采用,两者都采用了先进的软件技术进行设计,为了方便应用开发两者都采用了先进的设计模式.两者在框架设计上都采用了什么技 ...

  9. Android 框架式编程 —— 起篇

    一般的,在开发的时候,写过的代码在需求变更后,发现需要改动非常多的地方,那么说明之前的代码的架构肯定是存在问题的. 下面我们结合面向对象的六大基本原则谈Android 框架式编程.首先先介绍一下面向对 ...

  10. android 框架层 常用类介绍

    名称 功能描述 示意图 activitymanager 管理应用程序的周期并提供常用的回退功能 window manager 窗口管理者 content provider 用于访问另一个的数据,或者共 ...

随机推荐

  1. 设计模式之 Observer Pattern 观察者模式

    1.Subject通过一个容器保存零到多个Observer. 2.Subject通过Add,Delete方法调整Observer. 3.Subject的notifyObservers方法实际是逐个调用 ...

  2. x的平方根

    class Solution { public: /** * @param x: An integer * @return: The sqrt of x */ int getResult(long s ...

  3. ES6-个人学习笔记一--let和const

    es6已经推出一段时间了,虽然在兼容和应用上还有不少的难题,但是其提供的未来前端代码编程的发展趋势和一些好用的功能还是很吸引人的,因此个人买了'阮一峰'先生的es6入门,希望对其有一个了解和学习,本系 ...

  4. Python Standard Library 学习(一) -- Built-in Functions 内建函数

    内建函数列表 Built-in Functions abs() divmod() input() open() staticmethod() all() enumerate() int() ord() ...

  5. Linux脚本

    放置在/usr/local/sbin下面: 收到一个问题:"-bash XXX 没有权限":需要在此目录下执行chmod +x filename 收到一个问题:"-bas ...

  6. C51应用 Modbs Rtu协议实现与KEPServerEx 通信

    最近一客户要求使用STC12C5A60S2实现Modbus Rtu协议与KEPServerEx V4.0软件通信,采集单片机P2口每位的状态,设置P0口每位的状态,实现三路AD转换其中一路采集的是C0 ...

  7. wampsever 数据库初体验

    Wamp就是Windos Apache Mysql PHP集成安装环境,即在window下的apache.php和mysql的服务器软件.PHP扩展.Apache模块,开启/关闭鼠标点点就搞定,再 也 ...

  8. Mac上RoR环境搭建问题

    昨天一晚上折磨的我啊都快疯掉了. 按照http://railstutorial-china.org方法配制,到rvm requirements这个命令执行时就麻烦事来了. WutekiMacBook- ...

  9. BZOJ 3969 low power

    Description 有\(n\)个机器,每个机器有\(2\)个芯片,每个芯片可以放\(k\)个电池.每个芯片能量是\(k\)个电池的能量的最小值.两个芯片的能量之差越小,这个机器就工作的越好.现在 ...

  10. XP系统VPN设置

    为了解除公司上网策略限制,或者为了上Google,Facebook,都可以通过设置VPN实现. 要使用VPN需要到VPN服务商注册,链接VPN服务商. ======================== ...