辉夜的博客

繁花似锦,辉夜如昼

0%

网络通讯与数据存储

网络通信

网络请求框架对比:

  • 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. 发起网络请求
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) {

//创建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: 运行时处理

  • 注解定义
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())//利用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的代码

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 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二选一。