Android Retrofit★

1.Retrofit

Retrofit是基于OkHttp封装的网络请求框架,网络请求的工作本质上是OkHttp完成的,而Retrofit仅负责网络请求接口的封装。

OkHttp的缺点:

①配置网络请求非常繁琐,尤其是配置复杂网络请求body、请求头、参数的时候。

②获取结果后需要用户手动解析ResponseBody,难以复用。

③无法自动进行线程切换。

④如果存在嵌套网络请求,就会陷入“回调地狱”。

Retrofit封装OkHttp主要优化了以下几点:

①build模式创建网络请求基本配置。

②用注解类组合HTTP网络请求。

③提供Gson解析返回的json数据。

④Executor完成线程切换。

Retrofit请求实现的核心在于注解、动态代理和反射。通过对接口层的封装,将请求参数、header、url这些网络请求信息封装,然后交给OkHttp完成实际的请求操作。在服务端返回数据后,OkHttp将原始的结果交给Retrofit,然后Retrofit根据不同的场景进行不同的数据解析方式。

使用Retrofit,开发者不用关注网络通信的细节,只需要在接口文件中声明一系列方法和返回值,然后通过注解的方式指定该方法对应哪个服务器接口,以及需要提供哪些参数。当在程序中调用该方法时,Retrofit会自动向对应的服务器接口发起请求,并将响应的数据解析成返回值声明的类型。这样可以用更加面向对象的思维来进行网络操作。


2.Retrofit用法

①添加依赖

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

implementation 'com.squareup.retrofit2:converter-gson:2.3.0'

implementation("com.squareup.okhttp3:okhttp:4.9.1")

Retrofit是基于OkHttp二次封装的网络请求库, 所以要导入OkHttp的依赖。

gson是用来解析Json数据使用的。Retrofit也支持其他解析工具比如fastJson。

②build创建Retrofit实例

Retrofit mRetrofit = new Retrofit.Builder()

        .baseUrl(Config.baseUrl)

        .addConverterFactory( GsonConverterFactory.create())) //数据解析器

        .callbackExecutor( Executors.newSingleThreadExecutor())//线程池

        .build();

baseUrl:网络地址不能为空,且强制要求必须以斜杠/结尾。

callbackExecutor:使用单独的线程处理 (这很重要,一般网络请求如果不设置可能不会报错,但是如果是下载文件就会报错)。

③创建数据返回后的Bean类

public class MyLoginBean {

    private int code;

    private String msg;

    public int getCode() { return code; }

    public void setCode(int code) {

        this.code = code;

    }

    public String getMsg() { return msg; }

    public void setMsg(String msg) {

        this.msg = msg;

    }

}

④创建网络请求接口

public interface MyHttpList {

    @FormUrlEncoded

    @POST("test/login_test")

    Call<MyLoginBean> login(@Field("username") String username, @Field("password") String password);

}

这是一个接口类,MyLoginBean是数据返回后的Bean类,Retrofit会自动使用导入的Gson解析。@Field("username") 为post值的key。每个参数只能有一个注解。

注意:@POST("test/login_test")路径最前面不能加斜杠/,否则它会自动裁剪路径,这样会导致路径错误。

Retrofit把网络请求的url分成两部分:第一部分是在创建Retrofit对象的时候,通过baseUrl设置的;另一部分就是在这个接口当中通过注解的形式传入的。注意,如果在接口中注解后面设置的url是一个完整的路径或完整的网址,那在创建Retrofit对象的时候就不需要设置baseUrl了。

⑥发起同步网络请求

MyHttpList httpList = mRetrofit.create( MyHttpList.class); 

final Call<MyLoginBean> call = httpList.login("admin", "123456");

new Thread(new Runnable() {

    @Override

    public void run() {

        Response<MyLoginBean> response = call.execute(); //同步请求网络

        MyLoginBean bean = response.body();

        Log.e(TAG, "onResponse: code=" + bean.getCode() + " message=" + bean.getMessage());

    }

}).start();

首先用Retrofit.create()创建请求接口的代理,拿到call对象之后调用execute同步方法,返回一个response对象,然后通过response获取从后端请求返回的数据,因为gson解析器做好了解析,这里只需要response.body().getCode()、response.body().getMsg());就能获取服务端返回的json数据里面key对应value值。

create()方法内部使用到了观察者模式、代理模式以及外观模式。

注意:因为是同步方法,不能直接在ui线程里面操作,不然会造成线程阻塞直接报出anr,所以在使用call同步方法时,要开启一个子线程操作。

⑦发起异步网络请求

MyHttpList httpList = mRetrofit.create( MyHttpList.class);

Call<MyLoginBean> call = httpList.login( "admin", "123456");

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

    @Override

    public void onResponse(Call<MyLoginBean> call, Response<MyLoginBean> response) {

        MyLoginBean bean = response.body();

        Log.e(TAG, "onResponse: code=" + bean.getCode() + " message=" + bean.getMessage());

    }

    @Override

    public void onFailure(Call<MyLoginBean> call, Throwable t) {

        Log.e(TAG, "onFailure: 网络请求失败="+t.getMessage());

    }

});

调用call对象的enqueue异步方法,需要实现Callback接口里面的回调方法。因为是异步操作,所以不需要再开启线程来处理,框架已经处理好了。

⑧添加配置的OkHttpClient(主要使用请求超时/拦截器等功能)

如果Retrofit中需要设置请求超时时间、拦截器等时,可以使用OkHttp的方式来配置。

OkHttpClient okHttpClient = new OkHttpClient.Builder()

        .retryOnConnectionFailure(false) 

        .connectTimeout( 20,TimeUnit.SECONDS)

        .readTimeout(20,TimeUnit.SECONDS)

        .writeTimeout(20,TimeUnit.SECONDS)

        .addInterceptor() //设置拦截器

        .authenticator() //设置认证器

        .proxy()//设置代理

        .build();

mRetrofit = new Retrofit.Builder()

        .client(okHttpClient)

        ……

        .build();

 

3.源码分析

①构建Retrofit对象

Retrofit retrofit = new Retrofit.Builder()

    .baseUrl(URL)

    .callFactory(…)

    .addConverterFactory(GsonConverterFacto ry.create())

    .build();

Retrofit使用build()方法构建,通过设置各种工厂,为后面做好准备。

Retrofit.java:

public Retrofit build() {

    //1.设置callFactory属性为.callFactory()传入的参数。如果没有指定callFactory则默认为OkHttpClient。如果需要对OkHttpClient进行详细的设置,就需要自己构建并传入OkHttpClient对象

    okhttp3.Call.Factory callFactory = this.callFactory;

    if (callFactory == null) {

        callFactory = new OkHttpClient();

    }     

    //2.设置callbackExecutor属性为.callbackExecutor()传入的参数。如果没有指定就获取platform(Android平台)的defaultCallbackExecutor,最终获取到的是一个MainThreadExecutor,它里面有一个主线程的Handler,调用MainThreadExecutor的execute就可以使用Handler向主线程post一个任务

     Executor callbackExecutor = this.callbackExecutor; 

    if (callbackExecutor == null) {

        callbackExecutor = platform.defaultCallbackExecutor();

    } 

    //3.设置callAdapterFactories属性,其中CallAdapter.Factory主要用于对retrofit.Call对象进行转化,其中的优先级顺序为:①外界传入的callAdapterFactories②platform.defaultCallAdapterFactories()

    List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);

     callAdapterFactories.addAll( platform.defaultCallAdapterFactories(callbackExecutor));

    //4.设置converterFactories属性,其中Converter.Factory主要用于转化数据,例如将返回的ResponseBody转化为对象等。其中的优先级顺序:①BuiltInConverters②外界传入的converterFactories③platform.defaultConverterFactories()

      List<Converter.Factory> converterFactories = new ArrayList<>(1+this.converterFactories.size() + platform.defaultConverterFactoriesSize());

      converterFactories.add(new BuiltInConverters());

      converterFactories.addAll( this.converterFactories);

      converterFactories.addAll( platform.defaultConverterFactories());

    //5.通过设置的这些参数构建Retrofit对象并返回

      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories), unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly); 

}

build方法主要给几个重要参数赋值,分别是:callFactory、callbackExecutor、callAdapterFactories、converterFactories。

callFactory是网络请求器的工厂,用于生产Call请求对象,不管是同步请求还是异步请求都是通过这个Call来调用的。从这里也可以看出,在Retrofit内部默认使用的是okhttp的请求方式。

adapterFactories是网络请求适配器工厂的集合,用于放置网络请求适配器工厂。网络请求适配器工厂是用于生产CallAdapter网络请求适配器的。

converFactories是数据转换器工厂的集合,用于放置数据转换器工厂。数据转换器工厂是用于生产数据转换器的,比如可以放入Gson作为转换器,服务器返回数据为Json类型,然后通过Gson解析器进行解析,并在主线程中去显示。

callbackExecutor是回调方法的执行器,主线程切换到子线程,子线程切换到主线程,都是通过这个Executor来执行的。

②retrofit.create()生成代理对象

使用Retrofit进行网络请求的时候,需要先定义一个接口类,然后调用retrofit.create(serviceClass)生成接口的实例。retrofit.create()把网络请求配置的接口转换成一个实现了该接口的对象,使用的核心技术就是JDK动态代理。

Retrofit.java:

public <T> T create(final Class<T> service) {

    // 动态代理,返回代理对象

    return (T) Proxy.newProxyInstance( service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() {

      private final Object[] emptyArgs = new Object[0];  // 定义空的参数数组

      //每次调用接口中的方法都会走该方法,相当于就是接口方法的实现。参数proxy:代理对象,method:当前调用的接口方法,args:方法的参数

      @Override public Object invoke(Object proxy, Method method, Object[] args) {

            if (method.getDeclaringClass() == Object.class) { // 如果是Object类中的方法则不做额外处理

                 return method.invoke(this, args);

            }

            // 重点,获取一个ServiceMethod对象,然后调用它的invoke方法,网络请求的具体实现、处理就在这里

            return loadServiceMethod(method) .invoke(args != null ? args : emptyArgs);

          }

      });

}

retrofit.create()方法创建并返回了一个代理对象。在InvocationHandlerinvoke方法里调用了loadServiceMethod方法获取一个ServiceMethod对象,一个ServiceMethod对象就代表网络请求接口里的一个方法,获取到ServiceMethod后,调用它的invoke方法进行网络请求。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值