网络通信
网络请求框架对比:
- HttpURLConnection
- Volley
- OkHttp
- Retrofit
- 可以通过注解配置请求
- 可以搭配转换器解析数据,支持jackjson,pb等
Retrofit简介
Retrofit其实是对OkHttp的一个封装,使用Retrofit库的基本流程包括引用、创建用于描述网络请求的接口、使用Retrofit实例发起网络请求。
场景:客户端知道用户uid,要在服务端查询用户姓名,通过Retrofit实现
- 接口:
https://www.bytedane.com/{uid}/name
- 类型:GET请求
- 接口返回:
1 2 3 4 5 6 7 8 9
| { "message": "success", "data" : { "uid": "1123", "first_name":"张", "last_name":"三丰" }
}
|
1.导入dependencies依赖
1 2 3
| dependencies { implementation 'com.squareup.retrofit2:retrofit:2.4.0' }
|
2.创建用于描述网络请求的接口
1 2 3 4 5 6 7
| 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| fun getUserName(View) { val retrofit = Retrofit.Builder() .baseUrl("https://www.bytedance.com/") .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: 运行时处理
1 2 3 4 5
| @Target(METHOD) @Retention(RUNTIME) public @interface GET { String value() default ""; }
|
可以利用Method类的接口来获取注解的内容。配合动态代理可以获取方法和参数的注解,构造Request对象。
1 2 3 4
| public static Object newProxyInstance(ClasslLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
|
1 2 3 4
| public interface InvocationHandler{ public Object invoke(Object proxy, Method method, Object[] args) throw Throwable; }
|
之后可以通过Method.getAnnotaion()
和Method.getParameterAnnotation()
来获取方法和方法参数的注解内容。
代码分析
Retrofit的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| Retrofit retrofit = new Retrofit.builder() .baseUrl("http://www.bytedance.com/") .addConverterFactory(GsonConverterFactory.create()) .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的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| 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) { } });
|
字节跳动网络库
Cronet用C++实现,对OkHttp进行了特定优化。对其进行二次封装,设计一个高已用、功能全面的框架。最终决定基于Retrofit进行二次开发,将底层的OkHttp替换为Cronet,这就是TTNet。
核心点就是将OkHttpClient和OkHttpCall的生成替换为OkHttp和Cronet二选一。