付费下载
下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
【移动应用开发技术】Android中Retrofit源码如何使用
这期内容当中在下将会给大家带来有关Android中Retrofit源码如何使用,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。简介Retrofit是Square推出的HTTP框架,主要用于Android和Java。Retrofit
将网络请求变成方法的调用,使用起来非常简洁方便。本文先简要介绍一下Retrofit的用法,然后具体分析其源码执行的流程。基本用法Retrofit把HTTPAPI变成Java的接口。下面是Retrofit官网的一个例子:public
interface
GitHubService
{
@GET("users/{user}/repos")
Call<List<Repo>>
listRepos(@Path("user")
String
user);
}在GithubService接口中有一个方法listRepos,这个方法用了@GET的方式注解,这表明这是一个GET
请求。在后面的括号中的users/{user}/repos是请求的路径,其中的{user}
表示的是这一部分是动态变化的,它的值由方法的参数传递过来,而这个方法的参数@Path("user")Stringuser即是用于替换{user}
。另外注意这个方法的返回值是Call<List<Repo>>。可以看出Retrofit
用注解的方式来描述一个网络请求相关的参数。上面才是开始,下面要发出这个网络请求:Retrofit
retrofit
=
new
Retrofit.Builder()
.baseUrl("/")
.addConverterFactory(GsonConverterFactory.create())
.build();
GitHubService
service
=
retrofit.create(GitHubService.class);
Call<List<Repo>>
repos
=
service.listRepos("octocat");
repos.enqueue(new
Callback<List<Repo>>()
{
@Override
public
void
onResponse(Call<List<Repo>>
call,
Response<List<Repo>>
response)
{
}
@Override
public
void
onFailure(Call<List<Repo>>
call,
Throwable
t)
{
}
});可以看出,先是构建了一个Retrofit对象,其中传入了baseUrl参数,baseUrl和上面的GET方法后面的路径组合起来才是一个完整的
url。除了baseUrl,还有一个converterFactory,它是用于把返回的httpresponse转换成Java
对象,对应方法的返回值Call<List<Repo>>中的List<Repo>>,其中Repo
是自定义的类。有了Retrofit对象,接着调用它的create方法创建了GitHubService
的实例,然后就可以调用这个实例的方法来请求网络了。调用listRepo方法得到一个Call对象,然后可以使用enqueue或者execute
来执行发起请求,enqueue是是异步执行,而execute是同步执行。Retrofit的基本用法就是这样,其它还有一些细节可以查看官网。源码分析我***次接触Retrofit的时候觉得这个东西挺神奇的,用法跟一般的网络请求不一样。下面就来看看Retrofit的源码是怎么实现的。Retrofit的创建从Retrofit的创建方法可以看出,使用的是Builder模式。Retrofit中有如下的几个关键变量://用于缓存解析出来的方法
private
final
Map<Method,
ServiceMethod>
serviceMethodCache
=
new
LinkedHashMap<>();
//请求网络的OKHttp的工厂,默认是
OkHttpClient
private
final
okhttp3.Call.Factory
callFactory;
//baseurl
private
final
HttpUrl
baseUrl;
//请求网络得到的response的转换器的集合
默认会加入
BuiltInConverters
private
final
List<Converter.Factory>
converterFactories;
//把Call对象转换成其它类型
private
final
List<CallAdapter.Factory>
adapterFactories;
//用于执行回调
Android中默认是
MainThreadExecutor
private
final
Executor
callbackExecutor;
//是否需要立即解析接口中的方法
private
final
boolean
validateEagerly;再看一下Retrofit中的内部类Builder的builder方法:public
Retrofit
build()
{
if
(baseUrl
==
null)
{
throw
new
IllegalStateException("Base
URL
required.");
}
okhttp3.Call.Factory
callFactory
=
this.callFactory;
if
(callFactory
==
null)
{
//默认创建一个
OkHttpClient
callFactory
=
new
OkHttpClient();
}
Executor
callbackExecutor
=
this.callbackExecutor;
if
(callbackExecutor
==
null)
{
//Android
中返回的是
MainThreadExecutor
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的时候,如果没有指定OkHttpClient,会创建一个默认的。如果没有指定
callbackExecutor,会返回平台默认的,在Android中是MainThreadExecutor,并利用这个构建一个
CallAdapter加入adapterFactories。create方法有了Retrofit对象后,便可以通过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.如果是Object中的方法,直接调用
if
(method.getDeclaringClass()
==
Object.class)
{
return
method.invoke(this,
args);
}
//为了兼容
Java8
平台,Android
中不会执行
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方法接受一个Class对象,也就是我们编写的接口,里面含有通过注解标识的请求网络的方法。注意return语句部分,这里调用了
Proxy.newProxyInstance
方法,这个很重要,因为用了动态代理模式。关于动态代理模式,可以参考这篇文章:/blogs/d...。简单的描述就是,Proxy.newProxyInstance
根据传进来的Class对象生成了一个实例A,也就是代理类。每当这个代理类A执行某个方法时,总是会调用
InvocationHandler(Proxy.newProxyInstance中的第三个参数)的invoke
方法,在这个方法中可以执行一些操作(这里是解析方法的注解参数等),通过这个方法真正的执行我们编写的接口中的网络请求。方法解析和类型转换下面具体看一下在invoke中解析网络请求方法的几行。首先是ServiceMethodserviceMethod=
loadServiceMethod(method);,其中loadServiceMethod代码如下:ServiceMethod
loadServiceMethod(Method
method)
{
ServiceMethod
result;
synchronized
(serviceMethodCache)
{
result
=
serviceMethodCache.get(method);
if
(result
==
null)
{
result
=
new
ServiceMethod.Builder(this,
method).build();
serviceMethodCache.put(method,
result);
}
}
return
result;
}可以看出,这里是先到缓存中找,缓存中没有再去创建。这里创建了ServiceMethod对象。ServiceMethod用于把接口方法的调用转换成一个
HTTP请求。其实,在ServiceMethod中,会解析接口中方法的注解、参数等,它还有个toRequest方法,用于生成一个Request
对象。这个Request对象就是OkHttp中的Request,代表了一条网络请求(Retrofit实际上把真正请求网络的操作交给了OkHttp
执行)。下面是创建ServiceMethod的部分代码:public
ServiceMethod
build()
{
//获取
callAdapter
callAdapter
=
createCallAdapter();
responseType
=
callAdapter.responseType();
if
(responseType
==
Response.class
||
responseType
==
okhttp3.Response.class)
{
throw
methodError("'"
+
Utils.getRawType(responseType).getName()
+
"'
is
not
a
valid
response
body
type.
Did
you
mean
ResponseBody?");
}
//获取
responseConverter
responseConverter
=
createResponseConverter();
for
(Annotation
annotation
:
methodAnnotations)
{
//解析注解
parseMethodAnnotation(annotation);
//省略了一些代码
...
}
}在得到ServiceMethod对象后,把它连同方法调用的相关参数传给了OkHttpCall对象,也就是这行代码:OkHttpCall
okHttpCall=newOkHttpCall<>(serviceMethod,args);。下面介绍
OkHttpCall,OkHttpCall继承于Call接口。Call是Retrofit
的基础接口,代表发送网络请求与响应调用,它包含下面几个接口方法:Response<T>execute()throwsIOException;//同步执行请求voidenqueue(Callback<T>callback);//异步执行请求,callback用于回调booleanisExecuted();//是否执行过voidcancel();//取消请求booleanisCanceled();//是否取消了Call<T>clone();//克隆一条请求Requestrequest();//获取原始的requestOkHttpCall是Call的一个实现类,它里面封装了OkHttp中的原生Call,在这个类里面实现了execute以及enqueue
等方法,其实是调用了OkHttp中原生Call的对应方法。接下来把OkHttpCall传给serviceMethod.callAdapter对象,这里的callAdapter又是什么?在上面创建
ServiceMethod的代码中有一行代码:callAdapter=createCallAdapter(),这里创建了
calladapter,在这个代码内部是根据方法的返回类型以及注解去寻找对应的CallAdapter,去哪里寻找?去Retrofit对象的
adapterFactories集合中找。当我们创建Retrofit的时候,可以调用addCallAdapter向adapterFactories
中添加CallAdapter。在前面的基本用法里面,我们并没有添加任何CallAdapter,但adapterFactories中默认会添加一个
ExecutorCallAdapterFactory,调用其get方法便可获得CallAdapter对象。那么CallAdapter是干嘛的呢?上面调用了adapt方法,它是为了把一个Call转换成另一种类型,比如当Retrofit和
RxJava结合使用的时候,接口中方法可以返回Observable<T>,这里相当于适配器模式。默认情况下得到的是一个Call
对象,它是ExecutorCallbackCall,代码如下:public
CallAdapter<Call<?>>
get(Type
returnType,
Annotation[]
annotations,
Retrofit
retrofit)
{
if
(getRawType(returnType)
!=
Call.class)
{
return
null;
}
final
Type
responseType
=
Utils.getCallResponseType(returnType);
return
new
CallAdapter<Call<?>>()
{
@Override
public
Type
responseType()
{
return
responseType;
}
@Override
public
<R>
Call<R>
adapt(Call<R>
call)
{
return
new
ExecutorCallbackCall<>(callbackExecutor,
call);
}
};
}这个ExecutorCallbackCall接受一个callbackExecutor(Android中默认为
MainThreadExecutor,把返回的数据传回主线程)和一个call,也就是OkhttpCall。看下ExecutorCallbackCall
部分代码:static
final
class
ExecutorCallbackCall<T>
implements
Call<T>
{
final
Executor
callbackExecutor;
final
Call<T>
delegate;
ExecutorCallbackCall(Executor
callbackExecutor,
Call<T>
delegate)
{
this.callbackExecutor
=
callbackExecutor;
this.delegate
=
delegate;
}
@Override
public
void
enqueue(final
Callback<T>
callback)
{
if
(callback
==
null)
throw
new
NullPointerException("callback
==
null");
delegate.enqueue(new
Callback<T>()
{
@Override
public
void
onResponse(Call<T>
call,
final
Response<T>
response)
{
callbackExecutor.execute(new
Runnable()
{
@Override
public
void
run()
{
if
(delegate.isCanceled())
{
//
Emulate
OkHttp's
behavior
of
throwing/delivering
an
IOException
on
cancellation.
callback.onFailure(ExecutorCallbackCall.this,
new
IOException("Canceled"));
}
else
{
callback.onResponse(ExecutorCallbackCall.this,
response);
}
}
});
}
@Override
public
void
onFailure(Call<T>
call,
final
Throwable
t)
{
callbackExecutor.execute(new
Runnable()
{
@Override
public
void
run()
{
callback.onFailure(ExecutorCallbackCall.this,
t);
}
});
}
});
}在enqueue方法中,调用了OkHttpCall的enqueue,所以这里相当于静态的代理模式。OkHttpCall中的enqueue
其实又调用了原生的OkHttp中的enqueue,这里才真正发出了网络请求,部分代码如下:@Override
public
void
enqueue(final
Callback<T>
callback)
{
if
(callback
==
null)
throw
new
NullPointerException("callback
==
null");
//真正请求网络的
call
okhttp3.Call
call;
Throwable
failure;
synchronized
(this)
{
if
(executed)
throw
new
IllegalStateException("Already
executed.");
executed
=
true;
//省略了部分发代码
...
call
=
rawCal
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 外研八下英语Unit 1 Starting out-Understanding ideas《合作探究二》课件
- (新教材)2026人教版二年级下册数学 练一练p31-p32 课件
- 2025 高中信息技术数据结构在智能家居能源消耗预测与管理课件
- 2026年员工参股合同(1篇)
- 2026年借款及担保合同(1篇)
- 预制菜发展可行性研究报告
- 粮食烘干塔项目可行性研究报告
- 2026年及未来5年市场数据中国增效磷行业发展监测及投资战略咨询报告
- 信息技术教师资格证中计算机系统的工作原理
- 四川省德阳市高中2023级第二次诊断考试数学(含答案)
- 单兵战术动作低姿匍匐前进教案
- 2025新人教版七年级下册英语 Unit 8知识点梳理及语法讲义(答案版)
- 水库安全管理培训
- 2024年数智工程师职业鉴定考试复习题库(含答案)
- 工程劳务外包合同范本大全
- 统编版语文四年级下册 第一单元基础过关卷(试题)
- 自考《13180操作系统》考前强化练习试题库及答案
- 人工智能芯片设计 课件 周巍 第4-7章-人工智能与深度学习 -人工智能芯片架构设计
- 医院患者安全与防范措施管理规章制度
- DB34∕T 3463-2019 钢筋桁架楼承板系统应用技术规程
- 人教A版2019必修第一册专题3.2函数的基本性质【十大题型】(原卷版+解析)
评论
0/150
提交评论