康佳电视 背光维修LED55IS95D背光一亮几秒即灭求助

您还可以使用以下方式登录
当前位置:&>&&>&&>& > 【Android】Retrofit的使用(3)-对Retrofit进行简单的封装
android retrofit封装 【Android】Retrofit的使用(3)-对Retrofit进行简单的封装
1.创建一个ApiMnanager类用来管理Retrofit的实例化操作/** * Created by ccwant on . */public class ApiManager {
//网络缓存目录
private File httpCacheD
//网络缓存大小
private int cacheSize = 10 * 1024 * 1024; // 10 MiB
//网络连接超时时间,单位/秒
private int connTimeout=6;
//网络缓存对象
private OkHttpC
public ApiManager(Context context){
this.context=
private void initClient(){
httpCacheDir=new File(context.getCacheDir(),&okhttp&);
cache= new Cache(httpCacheDir, cacheSize);
//创建OkHttp
client = new OkHttpClient();
client.setConnectTimeout(connTimeout, TimeUnit.SECONDS);
client.setCache(cache);
* 获取对应服务
* @param service
T getApi(String url,Class service){
return getApi(url,service,null);
* 获取对应服务
* @param service
* @param listener
T getApi(String url,Class service,ProgressResponseListener listener){
initClient();
if(listener!=null){
client.interceptors().add(new DownloadProgressInterceptor(listener));
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)//传递url
.client(client)
.addConverterFactory(JsonConverterFactory.create())//添加返回值解析器
return retrofit.create(service);
}}2.设置文件上传与下载的监听方法第一步:封装一个的网络回调方法/** * Created by ccwant on . * 网络通讯回调接口 */public interface OnHttpCallBack {
public void onSuccess(T entity);
public void onFailure(Throwable t);
public void onResponseProgress(long progress, long total, boolean done);
public void onRequestProgress(long progress, long total, boolean done);}第二步:单独封装文件上传的监听方法/** * 请求体进度回调接口,比如用于文件上传中 * Created by ccwant on . */public interface ProgressRequestListener {
void onProgress(long progress, long total, boolean done);}第三步:单独封装文件下载的监听方法/** * Created by ccwant on . */public interface ProgressResponseListener {
* @param progress
已经下载或上传字节数
* @param total
* @param done
void onProgress(long progress, long total, boolean done);}第四步:创建网络下载进度拦截器/** * 网络下载进度拦截器 * Created by ccwant on . */public class DownloadProgressInterceptor implements Interceptor {
private String TAG=&DownloadProgressInterceptor&;
private ProgressResponseL
public DownloadProgressInterceptor(ProgressResponseListener listener){
this.listener=
public Response intercept(Chain chain) throws IOException {
Response orginalResponse = chain.proceed(chain.request());
return orginalResponse.newBuilder().body(new ProgressResponseBody(orginalResponse.body(),listener)).build();
}}第五步:包装请求体/** * 包装的请求体,处理进度 * Created by ccwant on . */public
class ProgressRequestBody extends RequestBody {
//实际的待包装请求体
private final RequestBody requestB
//进度回调接口
private final ProgressRequestListener progressL
//包装完成的BufferedSink
private BufferedSink bufferedS
* 构造函数,赋值
* @param requestBody
待包装的请求体
* @param progressListener 回调接口
public ProgressRequestBody(RequestBody requestBody, ProgressRequestListener progressListener) {
this.requestBody = requestB
this.progressListener = progressL
* 重写调用实际的响应体的contentType
* @return MediaType
public MediaType contentType() {
return requestBody.contentType();
* 重写调用实际的响应体的contentLength
* @return contentLength
* @throws IOException 异常
public long contentLength() throws IOException {
return requestBody.contentLength();
* 重写进行写入
* @param sink BufferedSink
* @throws IOException 异常
public void writeTo(BufferedSink sink) throws IOException {
if (bufferedSink == null) {
bufferedSink = Okio.buffer(sink(sink));
requestBody.writeTo(bufferedSink);
//必须调用flush,否则最后一部分数据可能不会被写入
bufferedSink.flush();
* 写入,回调进度接口
* @param sink Sink
* @return Sink
private Sink sink(Sink sink) {
return new ForwardingSink(sink) {
//当前写入字节数
long bytesWritten = 0L;
//总字节长度,避免多次调用contentLength()方法
long contentLength = 0L;
public void write(Buffer source, long byteCount) throws IOException {
super.write(source, byteCount);
if (contentLength == 0) {
//获得contentLength的值,后续不再调用
contentLength = contentLength();
//增加当前写入的字节数
bytesWritten += byteC
progressListener.onProgress(bytesWritten, contentLength, bytesWritten == contentLength);
}}第六步:包装返回体/** * 包装的接收体,处理进度 * Created by ccwant on . */public class ProgressResponseBody extends ResponseBody {
//实际的待包装响应体
private final ResponseBody responseB
//进度回调接口
private final ProgressResponseListener progressL
//包装完成的BufferedSource
private BufferedSource bufferedS
* 构造函数,赋值
* @param responseBody 待包装的响应体
* @param progressListener 回调接口
public ProgressResponseBody(ResponseBody responseBody, ProgressResponseListener progressListener) {
this.responseBody = responseB
this.progressListener = progressL
* 重写调用实际的响应体的contentType
* @return MediaType
@Override public MediaType contentType() {
return responseBody.contentType();
* 重写调用实际的响应体的contentLength
* @return contentLength
* @throws IOException 异常
@Override public long contentLength() throws IOException {
return responseBody.contentLength();
* 重写进行包装source
* @return BufferedSource
* @throws IOException 异常
@Override public BufferedSource source() throws IOException {
if (bufferedSource == null) {
bufferedSource = Okio.buffer(source(responseBody.source()));
return bufferedS
* 读取,回调进度接口
* @param source Source
* @return Source
private Source source(Source source) {
return new ForwardingSource(source) {
//当前读取字节数
long totalBytesRead = 0L;
@Override public long read(Buffer sink, long byteCount) throws IOException {
long bytesRead = super.read(sink, byteCount);
//增加当前读取的字节数,如果读取完成了bytesRead会返回-1
totalBytesRead += bytesRead != -1 ? bytesRead : 0;
//回调,如果contentLength()不知道长度,会返回-1
progressListener.onProgress(totalBytesRead, responseBody.contentLength(), bytesRead == -1);
return bytesR
}}第七步:创建Retrofit工具类&&/** * Retrofit工具类 * Created by ccwant on . */public class RetrofitUtils {
* 获取RequestBody请求体
* 主要用于文件上传
* @param file 文件
* @param callBack 网络回调
* @return ProgressRequestBody
public static ProgressRequestBody getRequestBody(File file, Context context, OnHttpCallBack callBack){
RequestBody requetBody = RequestBody.create(MediaType.parse(&multipart/form-data&), file);
return new ProgressRequestBody(requetBody,new RequestProgressTransferCallback(context,callBack));
* 获取RequestBody请求体
* 主要用于文件上传
* @param file 文件
* @return RequestBody
public static RequestBody getRequestBody(File file){
return RequestBody.create(MediaType.parse(&multipart/form-data&), file);
}}第八步:在之前封装的ApiManager中修改添加拦截器 /**
* 获取对应服务
* @param service
* @param listener
T getApi(String url,Class service,ProgressResponseListener listener){
initClient();
if(listener!=null){
client.interceptors().add(new DownloadProgressInterceptor(listener));
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)//传递url
.client(client)
.addConverterFactory(JsonConverterFactory.create())//添加返回值解析器
return retrofit.create(service);
}3.文件上传LoginApi service=mApiManager.getApi(Config.baseUrl2,LoginApi.class);Map params = new HashMap&&();params.put(&file\&; filename=\&&+file.getName()+&&, RetrofitUtils.getRequestBody(file,context,callBack));Call call= service.uploadImage(params);4.文件下载 LoginApi service=mApiManager.getApi(Config.baseUrl3,LoginApi.class,new ResponseProgressTransferCallback(context,callBack));Call call= service.downloadImage();就爱阅读网友整理上传,为您提供最全的知识大全,期待您的分享,转载请注明出处。
欢迎转载:
推荐:    您还可以使用以下方式登录
当前位置:&>&&>&&>& > Retrofit的使用与深入学习(上)
Retrofit的使用与深入学习(上)
简单介绍Retrofit发送网络请求通过okHttp,okhttp的诸多好处与内部实现机制,相对于直接使用okhttp的好处在于,它支持对Response接收数据进行解析,支持RxJava。Retrofit和Volley一样,网络请求任务在背后线程中进行,返回结果的处理(或者说回调方法)在UI线程中执行。此外这里给出Retrofit2相对于Retrofit1的改进支持了在一个类型中的同步和异步,同时,一个请求也可以被真正地终止;Retrofit1之前是分开的,即需要定义两个方法每一个 call 对象实例只能被调用一次,request 和 response 都是一一对应的;若需多次重复请求,则建议每次请求前clone一个call对象Response 对象增加了:响应码(the reponse code),响应消息(the response message),以及读取相应头(headers)@Url ,允许你直接传入一个请求的 URL,定义如下方法@GETCall<list& repoContributorsPaginate(@Url String url); </list动态 URL ParameterString links = response.headers().get(&Link&);Call<list& nextCall = gitHubService.repoContributorsPaginate(nextLink); </list&基本使用一、引入依赖
compile &#39;com.google.code.gson:gson:2.6.2&#39;
compile &#39;com.squareup.retrofit2:retrofit:2.0.2&#39;
compile &#39;com.squareup.retrofit2:converter-gson:2.0.2&#39;
compile &#39;com.squareup.okhttp3:okhttp:3.2.0&#39;
一般使用Retrofit还会使用它和RxJava配套使用,因此还需要添加如下依赖
compile &#39;io.reactivex:rxjava:1.1.3&#39;
compile &#39;io.reactivex:rxandroid:1.1.0&#39;
compile &#39;com.squareup.retrofit2:adapter-rxjava:2.0.2&#39;
为了使用更多的java注解添加下面的依赖
provided &#39;org.glassfish:javax.annotation:10.0-b28&#39;二、定义网络业务接口Retrofit的网络请求都是写在一个接口中,并使用一定的注释如下面一组请求接口:注意接口中的每个方法的参数都需要使用标注,不采用标注将会报错。public interface MyApiEndpointInterface {
@GET(&users/{username}&) //note1
Call getUser(@Path(&username&) String username,@Header(&Cache-Control&) int maxAge);
@Headers({&Cache-Control: max-age=640000&, &User-Agent: My-App-Name&})//note2
@POST(&users/new&)
Call createUser(@Body User user,@Query(&sort&) String sort);
//user支持被gson序列化的一个类,如JavaBean
@FormUrlEncoded
@POST(&some/endpoint&)
Call someEndpoint(@FieldMap Map names);
@POST(&https://blog.csdn.net/&) //note3
Call<response& getUser(@Query(&name&) String name);
@Multipart
@POST(&some/endpoint&)
Call uploadImage(@Part(&description&) String description, @Part(&image&) RequestBody image)
@GET(&users/{username}&) //note5
void getUser(@Path(&username&) String username, Callback cb);}</response1、Retrofit的网络请求返回的结果都是call的形式,?代表希望对Response body解析得到的数据类型;如果想直接获得Responsebody中的内容,可以定义网络请求返回值为Call2、Retrofit的注解有如下几种常见注解@GET 发送get方法的请求,@POST发送post方法的请求,@Header 网络请求的Header部分的键值对@Body Post请求报文的Body内容,内容往往是一个对Java Bean解析后得到的JSON String,@Path网络路径的缺省值,@Query网络请求地址后面的查询键值对,如/s?wd=REST&rsv_spt=1.@FormUrlEncoded 和 @FieldMap配套使用,用于向Post表单传入键值对3、一旦创建一个Retrofit实例就意味着网络请求根目录已经确定,但是Retrofit支持动态改变网络请求根目录。4、使用@Multipart 标注的网络请求,用于上传文件;同时该请求必须在请求方法的参数中有一个使用@Part注解的参数。下面给出一个简单的使用例子MediaType MEDIA_TYPE_PNG = MediaType.parse(&image/png&);file = new File(&/storage/emulated/0/Pictures/MyApp/test.png&);RequestBody requestBody = RequestBody.create(MEDIA_TYPE_PNG, file);Call call = apiService.uploadImage(&test&, requestBody);5、用于发送一个异步请求,不过在Retrofit2中已经没有这个了,异步请求和同步请求已经被合并。即通过Call的execute和queue方法分别发送同步和异步请求&三、得到网络业务接口的实体public static final String BASE_URL = &/&;Retrofit retrofit = new Retrofit.Builder() //note1
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create()) //gson负责对Response数据进行解析
.build();MyApiEndpointInterface apiService =
retrofit.create(MyApiEndpointInterface.class); //note21、获得一个Retrofit对象2、由retrofit得到一个网络请求接口的实现类&四、使用接口实体获取ResponseCall call = apiService.getUser(&evan&,5000);同步请求:Response response = call.execute();异步请求:call.enqueue(new Callback() {
public void onResponse(Call call, Response response) {
}});call只能使用一次,调用第二次的时候,就会出现失败的错误。当你想要多次请求一个接口的时候,直接用 clone 的方法来生产一个新的,相同的可用对象,clone代价很低。Retrofit2 中 Response 对象增加了曾经一直被我们忽略掉的重要元数据:响应码(the reponse code),响应消息(the response message),以及读取相应头(headers){cookies}。五、关于授权//note1Interceptor interceptor = new Interceptor() {
public okhttp3.Response intercept(Chain chain) throws IOException {
Request newRequest = chain.request().newBuilder().addHeader(&User-Agent&, &Retrofit-Sample-App&).build();
return chain.proceed(newRequest);
}};//note2OkHttpClient.Builder builder = new OkHttpClient.Builder();builder.interceptors().add(interceptor);builder.cache(new Cache(new File(&C:\\okhttp&),10*)) ;OkHttpClient client = builder.build();//note3Retrofit retrofit = new Retrofit.Builder()
.baseUrl(&&)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();1、创建拦截器,拦截器的工作就是在发送请求前在请求报文的header中添加一些键值对2、添加前面的拦截器到client中,为了提高网络访问效率我们还为OkHttp设置了缓存,到此为止跟okhttp的操作都是一样的3、为Retrofit设置个性化OkHttpClient对象&六、Retrofit和RxJava的配套使用PartA 定义网络业务接口public interface MyApiEndpointInterface {
@GET(&/users/{username}&)
Observable getUser(@Path(&username&) String username);
@POST(&/users/new&)
Observable createUser(@Body User user);}网络请求方法的返回值由之前的call转变成Observable, ?类支持使用gson对其进行序列化&PartB 得到网络业务接口的实体RxJavaCallAdapterFactory rxAdapter = RxJavaCallAdapterFactory.create(); //note1RxJavaCallAdapterFactory rxAdapter = RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io()); //note2Retrofit retrofit = new Retrofit.Builder()
.baseUrl(&&)
.addConverterFactory(GsonConverterFactory.create());
.addCallAdapterFactory(rxAdapter)
.build();MyApiEndpointInterface apiService =
retrofit.create(MyApiEndpointInterface.class); //note31、默认发送同步的网络请求2、默认发送异步的网络请求3、获取网络请求实体PartC使用示例String username = &sarahjean&;Observable call = apiService.getUser(username); //note1Subscription subscription = call //note2.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber() {
public void onCompleted() {
public void onError(Throwable e) {
if (e instanceof HttpException) {
HttpException response = (HttpException)e;
int code = response.code();
public void onNext(User user) {
}});1、获取到Observable之后的使用与RxJava一样的使用流程2、这里要十分注意的是在Android的Activity和Fragment中使用Rxjava需要在对应的onDestroy方法中调用subscription.unsubscribe()方法,防止OOM&&源码学习在正式学习源码之前首先看看我们想要了解的内容有哪些?Retrofit对象的创建需要哪些元素;该对象内部保存有哪些元素Retrofit对象的create方法返回的对象和传进去的接口有何种关联业务接口使用各种注解对方法会产生何种影响?常用注解@GET、@POST、@MultiPart、@FieldMap等作用效果Retrofit的ConverterF CallAdapterFactory方法设置的Converter.Factory和CallAdapter.Factory对象何时何地起作用Call对象及其execute和queue方法的内部逻辑Observable相对于RxJava有什么特殊的地方Response类型内部结构,有哪些数据可以访问&Retrofit.classRetrofit类中存储有如下的对象Fieldsprivate final HttpUrl baseU //网络请求基地址private final List converterF //数据转换器工厂集合private final List adapterF //网络请求适配器工厂集合private final okhttp3.Call.Factory callF //底层进行网络请求工厂private final Executor callbackE //回调方法执行器private final boolean validateE //是否提前对业务接口中的注解进行验证转换的标志位private final Map serviceMethodCache = new LinkedHashMap&&(); //ServiceMethod是对业务接口中方法的注解进行解析之后得到的对象,该对象包含了访问网络的除了方法参数值之外的所有必要信息;如数据转换器、网络请求适配器、网络请求工厂、基地址、Http方法等等。&Retrofit()@Retrofit.classRetrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
List converterFactories, List adapterFactories,
Executor callbackExecutor, boolean validateEagerly) {
this.callFactory = callF
this.baseUrl = baseU
this.converterFactories = unmodifiableList(converterFactories); //note1
this.adapterFactories = unmodifiableList(adapterFactories);
this.callbackExecutor = callbackE
this.validateEagerly = validateE}1、unmodifiableList(list)方法近似于UnmodifiableList(list);这样做的好处在于创建的新对象能够对list数据进行访问,但是不可通过该对象对list集合中的元素进行任何修改Builder.class@Retrofit.class该类中的域基本与Retrofit一样,但是多了一个如下的域private P&Builder()@Builder.classpublic Builder() {
this(Platform.get()); } //note1Builder(Platform platform) {
this.platform =
converterFactories.add(new BuiltInConverters()); //note2}1、如果是安卓系统则Platform.get()获取到的是一个如下的对象;也可以获得IOS、Java对应的类,很好很强大。static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
@Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
return new ExecutorCallAdapterFactory(callbackExecutor); //note4
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper()); //获取一个和Android UI线程绑定的Handler
@Override public void execute(Runnable r) {
handler.post(r);
} //异步任务在UI线程中执行
}}2、添加一个内置的转换器工厂到converterFactories中3、返回一个默认的回调方法执行器,该执行器负责在指定的线程中执行回调方法,Android就是将回调方法在UI线程中执行4、如果我们不准备将RxJava和Retrofit一起使用,一般都是使用的这个默认CallAdapter.Factory,因此我们在后面对ExecutorCallAdapterFactory.class源码进行解析,先不急着看等遇到了再去看。所以到此为止Builder默认创建了Converter.Factory、CallAdapter.Factory,Executor三个系统默认的数据转换器工厂、网络请求适配器工厂、回调执行器。可能大伙儿有点陌生,这些个工厂究竟是干嘛的?特此先跟大伙儿说几句,本节的末尾还会详谈:Converter.Factorypublic Converter responseBodyConverter(Type type, Annotation[] annotations,Retrofit retrofit) //对响应数据的解析public ConverterrequestBodyConverter(Type type,Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) //对请求数据的解析public ConverterstringConverter(Type type, Annotation[] annotations, Retrofit retrofit) //普通对象转件String 如JSONCallAdapter.Factorypublic abstract CallAdapterget(Type returnType, Annotation[] annotations, Retrofit retrofit) //获取网络请求适配器protected static Type getParameterUpperBound(int index, ParameterizedType type) { return Utils.getParameterUpperBound(index, type); }protected static ClassgetRawType(Type type) {return Utils.getRawType(type);}CallAdapterType responseType(); //该请求适配器返回的数据类型 T adapt(Call call); //该请求适配器对原始Call的再次封装,如Call到Observable &Build()@Builder.classpublic Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException(&Base URL required.&);} //note1
okhttp3.Call.Factory callFactory = this.callF //note2
if (callFactory == null) { callFactory = new OkHttpClient(); }
Executor callbackExecutor = this.callbackE //note3
if (callbackExecutor == null) { callbackExecutor = platform.defaultCallbackExecutor(); }
List adapterFactories = new ArrayList&&(this.adapterFactories); //note4
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
List converterFactories = new ArrayList&&(this.converterFactories); //note5
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories, callbackExecutor, validateEagerly);
}1、基地址检测2、网络请求执行器检测,若为空直接设置为OkHttpClient3、回调方法执行器检测,若为空直接设置为Buidler构造器中创建的Executor4、复制Builder中的List,并向该集合中添加Buidler构造器中创建的CallAdapter.Factory请求适配器,添加在集合器末尾5、复制Builder中的List,虽然该集合没有像前面第四步那样添加默认转换器,但是别忘了其实在Builder的构造器中已经向Builder中的List集合的第一个位置插入了一个默认的转换器。请求适配器工厂集合存储的是:自定义1适配器工厂、自定义2适配器工厂...默认适配器工厂数据转换器工厂集合存储的是:默认数据转换器工厂、自定义1数据转换器工厂、自定义2数据转换器工厂....&create()@Retrofit.classpublic
T create(final Class service) {
Utils.validateServiceInterface(service); //note1
if (validateEagerly) {
eagerlyValidateMethods(service); //note2
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class[] { service }, //note3
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, Object... args) throws Throwable {
if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); }
if (platform.isDefaultMethod(method)) {return platform.invokeDefaultMethod(method, service, proxy, args);}
ServiceMethod serviceMethod = loadServiceMethod(method); //note4
OkHttpCall okHttpCall = new OkHttpCall&&(serviceMethod, args); //note5
return serviceMethod.callAdapter.adapt(okHttpCall); //note6
});}1、判断该参数Service是不是一个接口,接口中是否有定义方法;否则抛出异常2、判断是否需要提前验证,方法内容就是给接口中的定义的每个方法的注解进行解析并得到一个ServiceMethod对象,并以Method为键将该对象存入LinkedHashMap集合中。如果不是提前验证则在第四步的时候会动态解析对应的方法,得到一个ServiceMethod对象,最后存入到LinkedHashMap集合中,有延迟加载的意思。默认都是延迟加载。eagerlyValidateMethods方法后面还有更为详细的介绍。3、创建一个代理&&java.lang.reflect.Proxy对象;Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces,InvocationHandler invocationHandler)方法近似于getProxyClass(loader, interfaces).getConstructor(InvocationHandler.class).newInstance(invocationHandler);从字面就可以知道,通过这个代理类,调用interfaces接口的方法实际上是通过调用InvocationHandler类型对象的invoke方法来完成指定的功能。4、如果代理类传进来的方法是一般方法则不会执行到这里,执行到这里表明调用的方法是我们使用了符合Retrofit规则的标注的方法。该行语句是从serviceMethodCache集合中获取一个对应的ServiceMethod对象。如果没有会临时创建一个ServiceMethod对象,再返回。loadServiceMethod方法后面也有更为详细的介绍。5、利用上面得到的ServiceMethod对象和方法参数创建一个OkHttpCall对象,该对象相对于okhttp3.Call会在网络请求前后对数据利用该方法对应的数据转换器进行一定的转换,之后内部再通过okhttp3.Call发送请求。OkHttpCall.class的相关方法在后面也会给出详细的介绍。6、将上面得到的OkHttpCall对象传给ServiceMethod中对应的网络请求适配器工厂的adapt方法中,返回的对象类型就是ServiceMethod对应的方法的返回值类型,如Call;&eagerlyValidateMethods()@@Retrofit.classprivate void eagerlyValidateMethods(Class service) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method)) {
loadServiceMethod(method); } //note1
}}1、非平台默认方法则加载解析该方法,并将得到的ServiceMethod对象加入到LinkedHashMap集合中。使用LinkedHashMap该集合的好处就是lruEntries.values().iterator().next()获取到的是集合最不经常用到的元素,提供了一种Lru算法的实现。loadServiceMethod()@Retrofit.classServiceMethod loadServiceMethod(Method method) {
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method); //note1
if (result == null) {
result = new ServiceMethod.Builder(this, method).build(); //note2
serviceMethodCache.put(method, result);
}}1、尝试从集合中获取该方法2、方法在集合中不存在,创建一个ServiceMethod对象,以method为键存入集合中。往下我们看看如何构建一个ServiceMethod对象&ServiceMethod.class
final okhttp3.Call.Factory callF
//方法使用的网络请求工厂
final CallAdapter callA
//方法使用的网络请求适配器
private final Converter responseC //方法的Response内容转换器
private final HttpUrl baseU //方法的基地址
private final String relativeU //方法的相对地址
private final String httpM
//方法的Http方法
private final H
//方法的http请求头 键值对
private final MediaType contentT //方法的http报文body的类型
private final boolean hasB
//方法的http是否有bod
private final boolean isFormE
private final boolean isM
private final ParameterHandler[] parameterH
//队方法参数的处理器,用于解析采用了标注的参数ServiceMethod()@ServiceMethod.classServiceMethod(Builder builder) {
this.callFactory = builder.retrofit.callFactory();
this.callAdapter = builder.callA
this.responseConverter = builder.responseC
this.baseUrl = builder.retrofit.baseUrl();
this.relativeUrl = builder.relativeU
this.httpMethod = builder.httpM
this.headers = builder.
this.contentType = builder.contentT .
this.hasBody = builder.hasB y
this.isFormEncoded = builder.isFormE
this.isMultipart = builder.isM
this.parameterHandlers = builder.parameterH}该对象包含了访问网络的所有基本的信息。内部类Builder.class@ServiceMethod.classFieldsfinal R //当前方法所属的Retrofitfinal M //当前方法final Annotation[] methodA //当前方法的注解final Annotation[][] parameterAnnotationsA //当前方法参数的注解ParameterHandler[] parameterH //当前方法参数的处理器final Type[] parameterT //当前方法参数的数据类型CallAdapter callA //请求适配器Type responseT //请求适配器的返回值类型Converter responseC //网络请求内容转换器String httpM //当前方法对应的http请求方法boolean hasB //当前请求是否有bodyString relativeU
//当前方法的相对URL地址Set relativeUrlParamN //当前方法的URL参数H //当前请求的header键值对boolean isM //当前请求是否是Multipartboolean isFormE // 一般设置了Multipart标签不能使用FormEncoded标签,该标签的使用参考前面的使用说明&Builder()@Builder.classpublic Builder(Retrofit retrofit, Method method) {
this.retrofit =
this.method =
this.methodAnnotations = method.getAnnotations(); //获取方法的注解
this.parameterTypes = method.getGenericParameterTypes(); //获取方法的参数类型
this.parameterAnnotationsArray = method.getParameterAnnotations(); //获取方法参数的注解}build()@Builder.classpublic ServiceMethod build() {
callAdapter = createCallAdapter(); //note1
responseType = callAdapter.responseType(); //note2
if (responseType == Response.class || responseType == okhttp3.Response.class) { throw ...} //note3
responseConverter = createResponseConverter(); //note4
for (Annotation annotation : methodAnnotations) { parseMethodAnnotation(annotation);
if (httpMethod == null) {
throw methodError(&HTTP method annotation is required (e.g., @GET, @POST, etc.).&); }
&&&&&if (!hasBody) {//note6
if (isMultipart) {throw methodError( &Multipart can only be specified on HTTP methods with request body (e.g., @POST).&); }
if (isFormEncoded) {throw methodError(&FormUrlEncoded can only be specified on HTTP methods with &+ &request body (e.g., @POST).&); }
int parameterCount = parameterAnnotationsArray. //note7
parameterHandlers = new ParameterHandler[parameterCount];
for (int p = 0; p & parameterC p++) {
Type parameterType = parameterTypes[p];
if (Utils.hasUnresolvableType(parameterType)) {throw parameterError(p, &Parameter type must not include a type variable or wildcard: %s&,parameterType); }
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
if (parameterAnnotations == null) {throw parameterError(p, &No Retrofit annotation found.&);}
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations); //note8
if (relativeUrl == null && !gotUrl) {throw methodError(&Missing either @%s URL or @Url parameter.&, httpMethod); } //note9
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {throw methodError(&Non-body HTTP method cannot contain @Body.&); }
if (isFormEncoded && !gotField) { throw methodError(&Form-encoded method must contain at least one @Field.&);}
if (isMultipart && !gotPart) { throw methodError(&Multipart method must contain at least one @Part.&);}
return new ServiceMethod&&(this);}1、近似于 callAdapter = retrofit.callAdapter(returnType, annotations);即根据方法返回值类型和注释从retrofit中获取对应的网络请求适配器。callAdapter方法是从Retrofit的adapterFactories集合中从0开始遍历,找到第一个满足要求的网络请求适配器。2、从前面的网络适配器(callAdapter)中获取该网络适配器返回的数据类型3、返回数据类型不可以为retrofit2.Response.class和okhttp3.Response.class类型,Response和Response是有区别的。4、近似于 responseConverter = retrofit.responseBodyConverter(responseType, annotations);即根据方法返回值类型和注释从retrofit中获取对应的转换器。responseBodyConverter方法是从Retrofit的converterFactories集合中从0开始遍历,找到第一个满足要求的内容转换器。5、对方法中的DELETE、GET、POST、HEAD、PATCH、PUT、OPTIONS、HTTP、retrofit2.http.Headers、Multipart、FormUrlEncoded几个标注进行处理,大多数标签都会调用方法parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody),该方法对ServiceMethod中的httpMethod、hasBody、relativeUrl、relativeUrlParamNames域进行赋值。6、请求报文中body中没有内容,但是使用了Multipart或者FormUrlEncode标注则抛出异常7、当前方法中参数个数,为每个参数创建一个arameterHandler8、为方法中的每个参数创建一个ParameterHandler对象,该对象的创建过程就对方法参数中的Body、PartMap、Part、FieldMap、Field、Header、QueryMap、Query、Path、Url标注进行解析9、后面就是一些判断了,最后创建ServiceMethod对象该方法内容比较多我们再次梳理一下:首先根据返回值类型和方法标注从Retrofit的网络请求适配器工厂集合和内容转换器工厂集合中分别获取到该方法对应的网络请求适配器和Response内容转换器;根据方法的标注对ServiceMethod的域进行赋值;最后为每个方法的参数的标注进行解析,获得一个ParameterHandler对象,该对象保存有一个Request内容转换器&&根据参数的类型从Retrofit的内容转换器工厂集合中获取一个Request内容转换器或者一个String内容转换器。&往下我们接着对create()@Retrofit.class中OkHttpCall okHttpCall = new OkHttpCall&&(serviceMethod, args);利用ServiceMethod和方法参数args创建的OkHttpCall类进行分析。Call.class首先简单看一下retrofit.Call接口的定义Response execute() throws IOE //执行同步请求void enqueue(Callback callback); //执行异步请求boolean isExecuted(); //当前请求是否执行完毕void cancel(); //取消当前请求boolean isCanceled(); //当前请求是否被取消Call clone(); //clone一个当前线程Request request(); //返回当前请求的请求对象&OkHttpCall.class如果我们没有特别给Retrofit设置一个请求适配器工厂,则Retrofit使用默认的请求适配器工厂&&ExecutorCallAdapterFactory.class,默认请求适配器工厂是存放在Retrofit的请求适配器工厂集合的末尾。通过ExecutorCallAdapterFactory得到Call对接收的网络请求没有经过任何特殊的处理直接交给OkHttpCall.class进行处理。证明分析见后面的ExecutorCallAdapterFactory.class源码部分。对于OkHttpCall类我们就分析下它的execute方法和enqueue方法。final class OkHttpCall implements CallOkHttpCall()@OkHttpCall.classFieldsprivate final ServiceMethod serviceM //构造器接收的参数private final Object[] //构造器接收的参数private okhttp3.Call rawC //实际进行网络访问的类private Throwable creationF //几个状态标志位privprivate volatOkHttpCall(ServiceMethod serviceMethod, Object[] args) {
this.serviceMethod = serviceM
this.args =}execute()@OkHttpCall.class@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException(&Already executed.&);
executed =
if (creationFailure != null) {
call = rawC
if (call == null) {
try { call = rawCall = createRawCall();
catch (IOException | RuntimeException e) {
creationFailure = }
if (canceled) {
call.cancel(); }
return parseResponse(call.execute()); //note2
}1、创建一个okhttp3.Call请求Request request = serviceMethod.toRequest(args); 该方法会对使用对应的ParameterHandler进行解析,并利用ServiceMethod中存储的headers等数据构造一个okhttp请求return serviceMethod.callFactory.newCall(request);近似于OkHttpClient.newCall(request)2、对请求结果解析,方法内部逻辑如下:Response parseResponse(okhttp3.Response rawResponse) {
ResponseBody rawBody = rawResponse.body();
int code = rawResponse.code();
if (code & 200 || code &= 300) { //响应执行失败
ResponseBody bufferedBody = Utils.buffer(rawBody);
return Response.error(bufferedBody, rawResponse);
if (code == 204 || code == 205) { //响应执行成功 但是没有返回数据body为空
return Response.success(null, rawResponse);
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
T body = serviceMethod.toResponse(catchingBody); //近似于serviceMethod.responseConverter.convert(body);//即使用ServiceMethod对应的Response内容转换器对接收到的数据进行转换。
return Response.success(body, rawResponse); //近似于return new Response&&(rawResponse, body, null);}以上过程就是整个网络请求的过程,首先对方法中每个参数利用对应ParameterHandler进行解析,再加上ServiceMethod中存储的Headers等数据创建一个okhttp的Request;使用okhttp发送这个请求;再对接收到的请求利用ServiceMethod存储的内容转换器对响应内容进行转换,最终得到一个Response对象。&enqueue()@OkHttpCall.class@Override public void enqueue(final Callback callback) {
if (callback == null) throw new NullPointerException(&callback == null&);
synchronized (this) {
if (executed) throw new IllegalStateException(&Already executed.&);
executed =
call = rawC
failure = creationF
if (call == null && failure == null) {
try { call = rawCall = createRawCall();}
catch (Throwable t) {failure = creationFailure =}
if (failure != null) { callback.onFailure(this, failure);}
if (canceled) {call.cancel();}
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) throws IOException {
response = parseResponse(rawResponse); //对响应数据进行解析
} catch (Throwable e) {
callFailure(e);
callSuccess(response);
}//end of onResponse
@Override public void onFailure(okhttp3.Call call, IOException e) {
try { callback.onFailure(OkHttpCall.this, e);}
catch (Throwable t) {t.printStackTrace();}
}//end of onFailure
private void callFailure(Throwable e) {
try {callback.onFailure(OkHttpCall.this, e); }
catch (Throwable t) { t.printStackTrace();}
private void callSuccess(Response response) {
try {callback.onResponse(OkHttpCall.this, response);}
catch (Throwable t) {t.printStackTrace();}
});}异步请求跟同步请求类似,也有创建okhttp请求,并对okhttp请求响应结果进行转换的过程;不同之处在于异步请求会将回调方法交给回调执行器在指定的线程中执行。对于okhttp的Call对象的enqueue、execute方法这里不再往下分析了,感兴趣的同学参考博客&到此为止,我们学习到的有:一、通过Retrofit的Builder内部类如何创建一个Retrofit对象,通过buidler设置baseUrl和可选的Converter.Factory、CallAdapter.Factory。二、调用Retrofit的create方法,根据create方法参数(接口类对象)构造一个代理,代理的执行实体是一个InnovationHandler对象。三、调用接口的所有方法最终都是通过调用InnovationHandler的invoke方法,invoke方法接收的参数主要有Method和args,invoke方法内部逻辑为:将Method对象转为一个ServiceMethod对象,构造过程会根据方法的标注从Retrofit的ArrayListconverterFactories和ArrayListadapterFactories集合中获取该方法对应的Converter responseConverters和CallAdaptercallAdapter,同时根据方法参数的标注为每个参数创建一个ParameterHandler对象,该对象包含有一个ConverterrequestConverter对象或者一个ConverterstringConverter对象;用于对每个参数进行转换处理。利用前面的ServiceMethod对象和args创建一个OkHttpCall对象,该对象内部会包含一个okhttp3.Call对象,OkHttpCall会在okhttp3.Call对象进行网络访问前后分别利用对应的requestConverter和responseConverter对数据进行相应的转换。通过ServiceMethod的callAdapter对象的adapter方法(参数OkHttpCall)创建一个本Method预期的返回值对象;如果在构造Retrofit的时候没有设置CallAdapter.Factory则都是返回的Call对象,该对象的execute方法和enqueue方法实际上都是直接调用OkHttpCall的同名方法,返回一个Response对象如果在构造Retrofit的时候设置了RxJavaCallAdapterFactory 那么可能返回对象可以定义为Observable类型,对于该类型我们的使用可以跟RxJava的使用一样,但是内部具体如何实现,我们还未曾介绍过。上面我们对学过的内容进行了总结,Retrofit基本上也了解的差不多了。往下深入分析就是对Converter.Factory和CallAdapter.Factory的分析就爱阅读网友整理上传,为您提供最全的知识大全,期待您的分享,转载请注明出处。
欢迎转载:
推荐:    

我要回帖

更多关于 康佳臻贵手机 的文章

 

随机推荐