关于android:Android-网络请求之Retrofit

1次阅读

共计 6451 个字符,预计需要花费 17 分钟才能阅读完成。

Android 网络申请之 Retrofit

一:前言
Retrofit 是一个 RESTful 的 HTTP 网络申请框架的封装,网络申请的工作实质上是 OKHttp 实现,而 Retrofit 仅负责网络申请接口的封装
Retrofit2 简略的说就是一个网络申请的适配器,它将一个根本的 Java 接口通过动静代理的形式翻译成一个 HTTP 申请,并通过 OkHttp 去发送申请。此外它还具备弱小的可扩展性,反对各种格局转换以及 RxJava
增加依赖:

implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'

前面两个是 rxJava 反对依赖,以及数据解析器
二:应用
第一步:创立用于形容网络申请的接口
Retrofit 将 Http 申请 形象成 Java 接口:采纳 注解 形容网络申请参数 和配置网络申请参数

public interface ApiService {@GET("users/{user}/repos")
    Call<List<Repo>> listRepos(@Path("user") String user);//@Path 传递的是网络申请参数,替换门路 {user} 下的内容
    // 比方你配置一个根门路是:http://myhost.com/
    这种等价于:GET: http://myhost.com/users/tom/repos
    
    // 获取工作, 上面这个是 Retrofit+RXJAVA 观察者模式的实现
    @POST("task/apply")
    Observable<BaseBean<GetTaskBean>> getTask(@Body RequestTaskBean requestTaskBean);
    }

第二步创立 Retrofit 实例

Retrofit retrofit =
                new Retrofit.Builder()
                        .client(okHttpClientBuilder.build())
                        .addConverterFactory(GsonConverterFactory.create())// 设置数据解析器
                        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())//RXJAVA 的适配器工厂
                        .baseUrl(HttpConfig.BASE_URL)// 设置网络申请的 url 地址
                        .build();

第三步:创立申请接口的实例

  // 创立 网络申请接口 的实例
        ApiService  request = retrofit.create(ApiService .class);

第四步:发送申请,同步申请和异步申请

 // 对 发送申请 进行封装
        Call<List<Repo>> call = request.listRepos("tom");
        call.enqueue(new Callback<List<Repo>>() {
            // 申请胜利时回调
            @Override
            public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
                // 申请解决, 输入后果
                response.body().show();
            }
            // 申请失败时候的回调
            @Override
            public void onFailure(Call<List<Repo>> call, Throwable throwable) {System.out.println("连贯失败");
            }
        });

          // 同步申请
        try {Response<List<Repo>> response = call.execute();
            response.body().show();
        } catch (IOException e) {e.printStackTrace();
        }

下面就是一个 Retrofit 应用的形式

三:Retrofit 注解
1. 注解类型:网络申请办法

注解代码 申请格局
@GET GET 申请
@POST POST 申请
@DELETE DELETE 申请
@HEAD HEAD 申请
@OPTIONS OPTIONS 申请
@PATCH PATCH 申请
@PUT PUT 申请
@DELETE DELETE 申请

下面对应的是 http 的申请形式,DELETE 申请:申请服务器删除 Request-URI 所标识的资源。PUT 申请:向指定资源地位上传其最新内容。TRACE 申请:回显服务器收到的申请,次要用于测试或诊断。
例如:

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

 // 比方你配置一个根门路是:http://myhost.com/
 // 下面就相当于:http://myhost.com/group/1/users?sort=mysort
 
 @POST("users/new")
Call<User> createUser(@Body User user);

2. 注解类型:标记类
我的项目中的申请头 Content-Type 的值为 multipart/form-data,这是一种十分常见的 POST 数据提交的形式,咱们在应用表单上传文件时就须要应用到这种形式。那我的我的项目申请里不须要上传文件啊,只是简略的键值对表单申请

注解代码 标记类
@FormUrlEncoded 申请头的 Content-Type 是 application/x-www-form-urlencoded
@Multipart 申请头的 Content-Type 是 multipart/form-data
@Streaming 申请头的 Content-Type
@Multipart
@POST("Sys/getVersion")
Observable<JsonObject> getNewVersion(@PartMap Map<String, RequestBody> versionBody);
// 通过学习 Retrofit2 的注解阐明,才晓得原来下面的 @Multipart 和 @PartMap 注解配合 Map<String, RequestBody> 参数是在多文件上传时用的,而这种形式默认的申请头 Content-Type 的值就是 multipart/form-data 

@FormUrlEncoded
@POST("Sys/getVersion")
Observable<JsonObject> getNewVersion(@FieldMap Map<String, String> versionBody);
// 我须要将 POST 数据提交的申请形式设置为表单的 @FormUrlEncoded,其对应的参数注解能够是 @FieldMap 或者 @Field,这是简略的键值对表单申请形式对应的注解组合

@Headers({"Content-Type: application/json","Accept: application/json"})
@POST("Sys/getVersion")
Observable<JsonObject> getNewVersion(@Body RequestBody info);
// 咱们也能够看到响应头的 Content-Type 的值为 application/json; charset=utf-8,这阐明服务器的返回后果是 JSON 字符串,所以当咱们申请参数的格局是 JSON 字符串的时候,也是利用这个值,在申请接口处加上申请头



3. 注解类型:网络申请参数

注解代码 解释
@Header 增加不固定的申请头
@Headers 增加固定的申请头
@URL 间接传入一个申请的 URL 变量 用于 URL 设置
@Body 自定义类型的数据
@Path URL 地址的缺省值
@Field 发送 Post 申请 时提交申请的表单字段, 与 @FormUrlEncoded 注解配合应用
@FieldMap 同上,Map 的 key 作为表单的键
@Part 发送 Post 申请 时提交申请的表单字段, 与 @Field 的区别:性能雷同,但携带的参数类型更加丰盛,包含数据流,所以实用于 有文件上传 的场景, 与 @Multipart 注解配合应用
@PartMap 同上
@Query 用于 @GET 办法的查问参数(Query = Url 中‘?’前面的 key-value)
@QueryMap 同上
 @GET("/")    
   Call<String> cate(@Query("cate") String cate);
   // 如:url = http://www.println.net/?cate=android,其中,Query = cate

应用 Retrofit 就不得不提 RxJava
通过 RxJavaCallAdapterFactory 为 Retrofit 增加 RxJava 反对:

Retrofit retrofit = new Retrofit.Builder()
      .baseUrl("https://api.github.com")
      .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) 
      .build();

通过观察者模式

PersonalProtocol personalProtocol = retrofit.create(PersonalProtocol.class);
rx.Observable<PersonalInfo> observable  = personalProtocol.getPersonalListInfo(12);
 observable.subscribeOn(Schedulers.io()) 
                .observeOn(AndroidSchedulers.mainThread())// 最初在主线程中执行
                .subscribe(new Subscriber<PersonalInfo>() {
                    @Override
                    public void onCompleted() {}

                    @Override
                    public void onError(Throwable e) {// 申请失败}

                    @Override
                    public void onNext(PersonalInfo personalInfo) {// 申请胜利}
                });
                
   // 对应的接口更改成
   public interface PersonalProtocol {
    /**
     * 用户信息
     * @param page
     * @return
     */
    @FormUrlEncoded
    @POST("user/personal_list_info")
    Observable<PersonalInfo> getPersonalListInfo(@Field("cur_page") int page);
//    Call<Response<PersonalInfo>> getPersonalListInfo(@Field("cur_page") int page);
}

四:Retrofit 的源码解析
1.Retrofit2 的 build() 办法,剖析构建 Retrofit 实例的 build 办法

public Retrofit build() {if (baseUrl == null) {throw new IllegalStateException("Base URL required.");
      }

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {callFactory = new OkHttpClient();
      }

      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {callbackExecutor = platform.defaultCallbackExecutor();
      }

      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }

Retrofit 会和 OkHttp 一起应用,而咱们创立的时候没有传递 OkHttp 进去,build()这个办法外面会创立一个 OkHttpClient(),当然你能够在里面传递进入
下面咱们能够看到,如果一个 baseurl 为空的话,会抛出异样

2. 咱们看 create 办法创立一个接口的对象

 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();

          @Override 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);
          }
        });
  }

调用 create()办法会返回一个范型 T,咱们这里是 PersonalProtocol 对象,当 PersonalProtocol 调用本身办法的时候,因为它使用了动静代理,所以会调用 invoke 办法。invoke 办法内先将 method 转换为 ServiceMethod 对象,再将 serviceMethod 和 args 对象传入 OkHttpCall 构造方法中,返回一个 OkHttpCall,最初将 OkHttpCall 传入 adapt 办法,最初返回一个 Call 对象。
五:网络申请库的比照

结尾:在这条路上走上来,明珠会交到我手中。

正文完
 0