网络通信 | 青训营笔记

132 阅读3分钟

这是我参与「第四届青训营 」笔记创作活动的第7天 今天的内容是基于Retrofit的网络通讯

网络通信

网络请求框架对比:

  • HttpURLConnection
  • Volley
    • 停更
    • 不适合上传下载文件
  • OkHttp
    • 支持大文件上传下载
    • 性能更好
    • 一般需要二次封装
  • Retrofit
    • 可以通过注解配置请求
    • 可以搭配转换器解析数据,支持jackjson,pb等

Retrofit简介

Retrofit其实是对OkHttp的一个封装,使用Retrofit库的基本流程包括引用、创建用于描述网络请求的接口、使用Retrofit实例发起网络请求。

场景:客户端知道用户uid,要在服务端查询用户姓名,通过Retrofit实现

  • 接口:https://www.bytedane.com/{uid}/name
  • 类型:GET请求
  • 接口返回:
{
    "message": "success", 
    "data" : {
        "uid": "1123",
        "first_name":"张",
        "last_name":"三丰"
    }

}

1.导入dependencies依赖

dependencies {
  implementation 'com.squareup.retrofit2:retrofit:2.4.0'
}

2.创建用于描述网络请求的接口

interface IUserInfoService {

  @GET("users/{uid}/name")
  fun getUserName(@Path("uid") uid: Int): Call<ResponseBody>

  ...
}
  • 接口类名:和请求的含义相关
  • 函数名:识别出该接口的作用,该Interface里可以增加多个不同的函数
  • @GET注解:指定该接口的相对路径,用get方法发起请求
  • @Path注解:需要外部调用时,用传入的uid替换注解里的{uid}
  • 返回值Call<ResponseBody>:可以直接转换把Sring转换为Model,这里就转换为User
  • ResponseBody:根据返回内容定义的类,应当包含所有字段和一些输出方法,response.body()是该类的一个实例
  1. 发起网络请求
fun getUserName(View) {
  
  //创建Retrofit实例
  val retrofit = Retrofit.Builder()
  .baseUrl("https://www.bytedance.com/")//请求Url地址
  .build()

  //创建 网络请求接口 的实例
  val iUserInterface = retrofit.create(IUserInfoService::class.java)
  val call = iUserInterface.getUserName(1123)

  //入队异步请求
  call.enqueue(object: Callback<ResponseBody> {

    override fun onResponse(call: Call<ResponseBody>,response: Response<ResponseBody>) {
      request_result_tv.text = "请求成功:" + response.body()!!.string();
    }

    override fun onFailure(call: Call<ResponseBody>, e: Throwable) {
      request_result_tv.text = "请求失败" + e.message
  }
  })
}

Retrofit注解

  • 注解简介 注解可以作用在类、方法、参数、成员变量上,并且可以在合适的时机读取注解并进行替换。 注解的处理一般有三个时机(Retention): 1.SOURCE: 只在源码有效 2.CLASS: 编译时用注解处理器处理 3.RUNTIME: 运行时处理

  • 注解定义

@Target(METHOD)//作用对象
@Retention(RUNTIME)//生命周期
public @interface GET {
  String value() default "";
}
  • 注解使用

可以利用Method类的接口来获取注解的内容。配合动态代理可以获取方法和参数的注解,构造Request对象。

public static Object newProxyInstance(ClasslLoader loader, 
Class<?>[] interfaces, 
InvocationHandler h)
  throws IllegalArgumentException
public interface InvocationHandler{
  public Object invoke(Object proxy, Method method, Object[] args)
  throw Throwable;
}

之后可以通过Method.getAnnotaion()Method.getParameterAnnotation()来获取方法和方法参数的注解内容。

代码分析

Retrofit的代码

Retrofit retrofit = new Retrofit.builder()
      .baseUrl("http://www.bytedance.com/")
      .addConverterFactory(GsonConverterFactory.create())//利用gson转换器解析json,需要添加gson依赖
      .build();

IUserInfoService iUserInterface = retrofit.create(IUserInfoService.class);

retrofit2.Call<ResponseBody> call = iUserInterface.getUserName(1123);

call.enqueue(new Callback<ResponseBody>() {
  
  @Override
  public void onResponse (Call<ResponseBody> call,
      Response<ResponseBody> response){

      }
  
  @Override
  public void onFailure(Call<ResponseBody> call,  Throwable t){

  }
})

OkHttp的代码

//创建OkHttpClient
OkHttpClient OkHttpClient = new OkHttpClient.Builder().build();


Request request = new Request.Builder()
    .get()
    .url("https://www.bytedance.com/user/1123/name")
    .build();
//
OkHttp.Call call = okHttpClient.newCall(request);

Call.enqueue(new Callback() {
  
  @Override
  public void onFailure (Call call, IOException e) {

  }

  @Override
  public void onResponse (Call call, Response response) {
    //TODO: 服务器响应结果
  }
});

字节跳动网络库

Cronet用C++实现,对OkHttp进行了特定优化。对其进行二次封装,设计一个高已用、功能全面的框架。最终决定基于Retrofit进行二次开发,将底层的OkHttp替换为Cronet,这就是TTNet。 核心点就是将OkHttpClient和OkHttpCall的生成替换为OkHttp和Cronet二选一。