1.网络通信
网络通信一直是Android项目里比较重要的一个模块,Android开源项目上出现过很多优秀的网络框架,从一开始只是一些对HttpClient和HttpUrlConnection简易封装使用的工具类,到后来Google开源的比较完善丰富的Volley,再到如今比较流行的 Okhttp 、 Retrofit 。
1.1 网络请求框架对比
请求方式 | 作者 | 包体积增量 | 使用成本 | 特点 | 使用场景 |
HttpURL Connection | AndroidSDK | 0KB | 2n | 需要自己做封装,例如线程池管理、返回的数据解析 | 只有少量网络请求的工具类App |
Volley | 57KB | n | 1.适合网络请求频繁、传输数据量小 2.不适合用来上传文件和下载 3.已停更 | 之前使用Volley,且无需大文件下载的App | |
OkHttp | square公司 | 262KB | 1.5n | 1.可以设置拦截器,支持大文件上传和下载 2.OkHttp基于NIO和Okio,性能更好 3.一般需要二次封装使用 | 一般比较少直接使用,通常搭配Volley和Retrofit |
Retrofit | square公司 | 343KB | 2n | 具备OkHttp的所有优点,且要更出色 1.restful api设计风格 2.通过注解配置请求,包括请求方法、请求参数、请求头等 3.可以搭配多种Converter将获得的数据解析,支持Gson、jackson、Protobur等 | 对Retrofit比较熟悉时使用 |
Retrofit是目前Android平台上,可以说是最热门的网络请求框架,是对OkHttp的一个封装。
1.2 Retrofit使用介绍
1.2.1 创建用于描述网络请求的接口
interface IUserInfoService {
@GET("users/{uid}/name ")
fun getUserName(@Path("uid") uid: Int): Call<ResponseBody>
//后续可以增加其他的接口,一个接口对应一个api请求
}
定义说明:
- 接口类名:可自定义,尽量和这类请求的含义相关
- 函数名:可自定义,需要能识别出该接口的作用,该interface里可以增加多个不同的函数
- @GET注解:用于指定该接口的相对路径,并采用Get方法发起请求
- @Path注解:需要外部调用时,传入一个uid,该uid会替换@GET注解里相对路径的{uid}
- 返回值Call<ResponseBody>:这里用ResponseBody,我们可以直接拿到请求的String内容如果要自动转为Model类,例如User,这里直接替换为User就好。
1.2.2 发起网络请求
1.2.2.1 创建Retrofit实例
1.2.2.2 创建请求接口的实例,并获取到Call实例
1.2.2.3 调用call.enqueue进行异步请求
1.2.2.4 处理返回的数据
fun getUserName(view: View) {
//创建 Retrofit实例
val retrofit = Retrofit.Builder()
.baseUrl("url") //设置网络请求的Url地址
.build()
//创建网络请求接口的实例
val iUserInfoService = retrofit.create(IUserInfoService::class.java)
val call = iUserInfoService.getUserName(key)
//enqueue是异步请求的接口
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
}
}
}
1.3 注解介绍
注解的处理,一般有3个时机(也就是注解的生命周期@Retention):
1.SOURCE:只有在源码中有效,编译时抛弃,例如前面的@Override
2.CLASS:编译class文件时有效,一般会使用到注解处理器。
3.RUNTIME:在运行期间,获取对应的注解,并做相关的处理。
1.3.1 Retrofit注解@GET定义
@Documented
@Target(METHOD)
@Retention(RUNTIME)
public @interface GET {
/**
* A relative or absolute path, or full URL of the endpoint. This value is optional if the first
* parameter of the method is annotated with {@link Url @Url}.
*
* <p>See {@linkplain retrofit2.Retrofit.Builder#baseUrl(HttpUrl) base URL} for details of how
* this is resolved against a base URL to create the full endpoint URL.
*/
String value() default "";
}
@Target:指定作用的对象,这里是METHOD,
说明这个注解是作用在方法上其他枚举值:
PARAMETER:参数
FIELD:类成员
@Retention:指定注解的生命周期,这里是RUNTIME,说明要这个注解要一直保留到运行时
1.3.2 注解的获取和使用
通过反射获取到Method对象后,有以下一些接口来获取注解内容1.Method.getGenericReturnType()获取返回类型
2.Method.getAnnotations()获取方法的注解
3.Method.getParameterAnnotations()获取参数注解
Method[] declaredMethods = IUserInfoService.class.getDeclaredHethods();
for (Method method : declaredMethods) {
Type type = method.getGenericReturnType();//正式返回类型
Annotation[] methodAnnotations = method.getAnnotations();//方法注解
Annotation[][] parameterAnnotationsArray = method. getParameterAnnotations();//方法参数注解
}
1.3.3 Java动态代理Proxy.newProxylnstance
- 利用Java的反射技术(Java Reflection),代理某个interface,一旦调用interface里的某个方法时,实际通过代理调用InvocationHandler的invoke方法
- 通过Method对象,就可以调用Method.getAnnotations()和Method.getParameterAnnotations()来获取该方法和方法参数的注解内容。
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
public interface InvocationHandler {
public Object invoke (Object proxy , Method method , Object[] args)
throws Throwable;
}
Retrofit是在运行期间,配合Java动态代理,获取方法和参数的注解,并构造Request对象的。
1.4 Retrofit主流程
1.通过Builder模式,创建RetrofitConfig,保存baseUrl等内容
2.创建动态代理对象
3.创建OkHttpCall
4.发起网络请求
1.4.1 Retrofit里OkHttpClient创建时机
Retrofit的Builder构造行数中如果未指定callFactory,则会自动创建一个OKHttpClient
注:这里留意下,有一个adapterFactories集合,里面包含一个默认的CallAdapter.Factory ,它是子类ExecutorCallAdapterFactory的实例
1.4.2 Retrofit里OkHttpClient创建时机
创建好的OKHttpClient将会保存在Retrofit实例中
ExecutorCallAdapterFactory主要是用来控制Retrofit在子线程触发请求,在主线程回调结果
1.4.3 OkHttpCall的创建
当我们通过代理对象调用我们的接口方法lUserlnfoService#getUserName()时,会触发lnvocationHandler#invoke方法
下图可以看到Retrofit写死了只支持OkHttp
1.5 TTNet类图设计
核心点主要替换其中的两点:
1.替换底层用到的OKHttpClient
2.替换底层用到的OKHttpCall
总结