Retrofit分析与实现

前言

估计很多人和我一样,在接触retrofit这个库的时候就被它强大的功能所吸引住了。它不同于传统的网络请求方式的是,retrofit巧妙的采用接口方式进行网络请求,每次调用接口方法,就是对应一次网络请求,这对于长期和丑陋接口做斗争的程序员来说这简直是莫大的福利啊。然而光是用肯定是不行,我们还得搞清其中的原理,知其why。一番周折之后,我发现自己在阅读源码并实现的过程中已经能作一文,于是写出来分享,算是学习中的心得体会。

示例

在开始之前,我们先看下一段简单的示例

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://10.21.59.21:8080/")
                .client(new OkHttpClient())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();

        m_weatherApi = retrofit.create(WeatherApi.class);

        findViewById(R.id.id_button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                final Observable<Weather> list = m_weatherApi.getWeather("json");
                list.observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.newThread())
                        .subscribe(new Subscriber<Weather>() {
                        ...
            }
        });

可以看到,在我们的例子中,我们首先创建了一个retrofit对象,这里使用的是Builder模式,创建过程中我们指定了网络请求时的uri, client, converterFactory (这也是这个库的核心之处),callAdapterFactory。
之后通过create方法,创建WeatherApi示例, 之后每次调用WeatherApi的方法都是对应于一次请求。
我们看下WeatherApi:

public interface WeatherApi {
   
   

    @GET("/{path}")//使用get方式进行Http请求
    //将上述的path替换成指定的path
    //在我们的例子里面 这里会被替换成 "json" 这个字符串
    Observable<Weather> getWeather(@Path("path") String path); 
}

这里都是GET注解 指定请求方式是get,GET中的值会添加在baseUrl中, Path注解指定了具体的请求path,它将替换本文中的{path}字符串为具体的值,在我们的例子中,最后的请求uri会变成:
http://10.21.59.21:8080/json

好了,这里只是简单的看下示例,也是为我们整个全文做个铺垫,读者在阅读过程中要时常记得返回到此,才能加深理解。当然如果您还不了解该库具体的使用方式,可以参考:[retrofit官网]
(http://square.github.io/retrofit/)

我在编写博文的过程中就已经思考过了,要想懂这个库为什么如此设计,光看源码肯定不行。首先要做的就是理解它的Description information, 如果你点击了上面的链接,就可以看到,在它官网首页,就标注了retrofit是一个类型安全的Http客户端(A type-safe HTTP client for Android and Java)。什么叫类型安全呢?为什么要类型安全?这的确有点难懂啊

Type Safe

从上面的示例代码我们就看到了,在进行网络请求的时候,我们制定了它的客户端——OkHttpClient。也就是说,真正的网络请求都是通过okhttp实现的。然而,我们都使用过okhttp,所以我们都应该知道,在获得服务器请求之后,我们都是通过Response对象来获得服务器返回的数据的,比如这样:

        Request request = ...;
        OkHttpClient okHttpClient = new OkHttpClient();
        com.squareup.okhttp.Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Request request, IOException e) {

            }

            /**
             * 这里获得服务器的数据
             * @param response
             * @throws IOException
             */
            @Override
            public void onResponse(Response response) throws IOException {
                ResponseBody responseBody = response.body();

                //二进制
                responseBody.bytes();
                //字符串
                responseBody.string();
            }
        });

获得的数据无非就是二进制类型或者字符串类型的。如果服务器返回的是json字符串,我们还得通过gson把它转换成实体类对象。这显然是不够友好的,所以我们要改变。用户无需知道服务器返回的数据具体格式,我们只要知道它最终的类型就好了Book? Person?etc。屏蔽这些细节,专心于业务实现岂不是更好。

而我们的retrofit如何做到的呢?那就是通过converterFactory 来实现了,它主要是负责将服务器返回的数据转换成具体的实例类对象。比如在我们这个例子里面,它的作用就是将服务器返回的json字符串转换成Book实体类对象。

分析实现方式

那么我们现在就根据上面的示例实现一个自己的retrofit,不过在开始之前还是需要分析一下实现方式

1:通过Retrofit.Builder对象new 一个Retrofit对象,期间需要配置的有:
(1):client,因为有时候我们可能需要在请求头加一个token头,用来作为访问服务器时验证其身份有效性的凭证。
(2):baseUrl,所有的请求Uri都是基于它的
(3):ConverterFactory, 一种工厂对象,用于根据用户指定的返回值类型,确定最终将服务器返回数据转换成对应实体类对象的Converter类型。在我们的例子里面GsonConverterFactory将选用GsonConverter来转换
(4):CallAdapterFactory,网络请求之后返回的是对应的Call< T >类型(这里的T对应于本文的Weather),然而如果我们结合RxJava使用的话,需要把它再做一次修饰,转换成Observable< T >类型。
2:注解:http请求是采用Get,post,还是delete,都需要根据描述接口方法的注解来确定,如果是Get的话,我们就需要生成get方式的Request对象,同理于Post Delete方式。所以我们需要一个RequestFactory,它根据方法的注解描述生成对于的Request对象。
3:通过动态代理,生成接口对应的对象,之后的每次方法Invoke都是上述组建之间互相配合

效果

我们先看下最终要到达的效果:

public class MainActivity extends AppCompatActivity {
   
   
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值