当前位置: 首页 > 科技观察

AndroidRetrofit源码具体使用分析

时间:2023-03-17 15:56:16 科技观察

介绍Retrofit是Square推出的一个HTTP框架,主要用于Android和Java。Retrofit将网络请求变成了方法调用,使用起来非常简单方便。本文先简单介绍一下Retrofit的用法,然后具体分析其源码执行的过程。基本用法Retrofit将HTTPAPI转换为Java接口。下面是Retrofit官网的例子:publicinterfaceGitHubService{@GET("users/{user}/repos")Call>listRepos(@Path("user")Stringuser);}有一个方法在GithubService接口listRepos中,这个方法被@GET注解,表示这是一个GET请求。下面括号中的users/{user}/repos是请求的路径,其中{user}表示这部分是动态变化的,它的值是通过方法的参数传递的,而这个方法的参数@Path("user")Stringuser用于替换{user}。另请注意,此方法的返回值为Call>。可以看出Retrofit使用注解来描述与网络请求相关的参数。以上是开始,要发出如下网络请求:Retrofitretrofit=newRetrofit.Builder().baseUrl("https://api.github.com/").addConverterFactory(GsonConverterFactory.create()).build();GitHubServiceservice=retrofit.create(GitHubService.class);Call>repos=service.listRepos("octocat");repos.enqueue(newCallback>(){@OverridepublicvoidonResponse(Call>call,Response>response){}@OverridepublicvoidonFailure(Call>call,Throwablet){}});可以看到,首先构造了一个Retrofit对象,传入baseUrl参数,baseUrl和上面GET方法后面的路径组合起来就是一个完整的url。除了baseUrl之外,还有一个converterFactory,用于将返回的http响应转换为Java对象,对应方法Call>返回值中的List>,其中Repo是自定义类。有了Retrofit对象,然后调用它的create方法创建一个GitHubService的实例,然后就可以调用这个实例的方法来请求网络了。调用listRepo方法得到一个Call对象,然后可以使用enqueue或者execute来执行请求。enqueue是异步执行,execute是同步执行。这是Retrofit的基本用法,还有一些其他的细节可以去官网查看。源码分析刚开始接触Retrofit的时候,觉得这个东西很神奇,它的用法和普通的网络请求不一样。下面来看看Retrofit的源码是如何实现的。Retrofit的创建从Retrofit的创建方法可以看出,使用的是Builder模式。Retrofit中有几个关键变量如下://方法privatefinalMapserviceMethodCache=newLinkedHashMap<>()用于缓存和解析;//请求网络OKHttp工厂,默认为OkHttpClientprivatefinalokhttp3.Call.FactorycallFactory;//baseurlprivatefinalHttpUrlbaseUrl;//请求网络得到的响应转换器的集合,默认会添加到BuiltInConvertersprivatefinalListconverterFactories;//将Call对象转换成其他类型privatefinalListadapterFactories;//用于executecallbacksAndroid中默认是MainThreadExecutorprivatefinalExecutorcallbackExecutor;//是否需要立即解析接口中的方法privatefinalbooleanvalidateEagerly;查看Retrofit内部类Builder的builder方法:publicRetrofitbuild(){if(baseUrl==null){thrownewIllegalStateException("BaseURLrequired.");}okhttp3.Call.FactorycallFactory=this.callFactory;if(callFactory==null){//默认创建一个OkHttpClientcallFactory=newOkHttpClient();}ExecutorcallbackExecutor=this.callbackExecutor;if(callbackExecutor==null){//Android返回的是MainThreadExecutorcallbackExecutor=platform.defaultCallbackExecutor();}//制作适配器的防御副本并添加默认调用适配器。列表<呼叫适配器。<>(this.converterFactories);returnnewRetrofit(callFactory,baseUrl,converterFactories,adapterFactories,callbackExecutor,validateEagerly);}创建Retrofit时,如果不指定OkHttpClient,会创建一个默认的。如果不指定callbackExecutor,则返回平台默认的,即Android中的MainThreadExecutor,并以此构建CallAdapter加入adapterFactories。create方法有了Retrofit对象后,就可以通过create方法创建网络请求接口类的实例了。代码如下:publicTcreate(finalClassservice){Utils.validateServiceInterface(service);if(validateEagerly){//分析方法eagerlyValidateMethods(service);}return(T)Proxy.newProxyInstance(service.getClassLoader(),newClass[]{service},newInvocationHandler(){privatefinalPlatformplatform=Platform.get();@OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object...args)throwsThrowable{//如果是一个Object中的方法,直接调用if(method.getDeclaringClass()==Object.class){returnmethod.invoke(this,args);}//为了兼容Java8平台,Android不会执行if(platform.isDefaultMethod(method)){returnplatform.invokeDefaultMethod(method,service,proxy,args);}//下面是重点,分析方法ServiceMethodserviceMethod=loadServiceMethod(method);OkHttpCallokHttpCall=newOkHttpCall<>(serviceMethod,args);returnserviceMethod.callAdapter.adapt(okHttpCall);}});create方法接受一个Class对象,也就是我们写的接口,里面包含了通过注解标识的请求网络的方法注意return语句的部分,这里调用了Proxy.newProxyInstance方法,这个很重要,因为使用了动态代理模式。关于动态代理模式,可以参考这篇文章:http://www.codekk.com/blogs/d...。简单的描述就是Proxy.newProxyInstance根据传入的Class对象生成一个实例A,即代理类。每当这个代理类A执行某个方法时,总会调用InvocationHandler的invoke方法(Proxy.newProxyInstance中的第三个参数),在这个方法中可以进行一些操作(这里是解析方法的注解参数等).),通过这个方法来真正执行我们写的接口中的网络请求。方法解析和类型转换我们看一下invoke中解析网络请求方法的几行代码。首先是ServiceMethodserviceMethod=loadServiceMethod(method);,其中loadServiceMethod代码如下:=newServiceMethod.Builder(this,method).build();serviceMethodCache.put(method,result);}}returnresult;}可以看出这里是先在缓存中查找,并没有在缓存中创建.这里创建了ServiceMethod对象。ServiceMethod用于将接口方法调用转换为HTTP请求。其实在ServiceMethod中,会解析接口中方法的注解和参数,它还有一个生成Request对象的toRequest方法。这个Request对象就是OkHttp中的Request,代表一个网络请求(Retrofit实际上是将实际的网络请求操作交给了OkHttp来执行)。下面是创建ServiceMethod的部分代码:){throwmethodError("'"+Utils.getRawType(responseType).getName()+"'isnotavalidresponsebodytype.DidyoumeanResponseBody?");}//获取responseConverterresponseConverter=createResponseConverter();for(Annotationannotation:methodAnnotations){//解析注解parseMethodAnnotation(注解);//部分代码省略...}}得到ServiceMethod对象后,连同方法调用的相关参数一起传递给OkHttpCall对象,即这行代码:OkHttpCallokHttpCall=newOkHttpCall<>(服务方法,参数);。下面介绍OkHttpCall,它继承自Call接口。Call是Retrofit的基础接口,代表发送网络请求和响应调用。它包含以下接口方法:Responseexecute()throwsIOException;//同步执行请求voidenqueue(Callbackcallback);//异步执行请求,callback用于回调booleanisExecuted();//voidcancel()是否已经执行;//取消请求booleanisCanceled();//是否取消Callclone();//克隆一个请求Requestrequest();//获取原始requestOkHttpCall是Call的一个实现类,封装了OkHttp中的nativeCall,在该类中实现了execute和enqueue方法,实际调用OkHttp方法中对应的nativeCall。接下来,将OkHttpCall传递给serviceMethod.callAdapter对象。这里的callAdapter是什么?上面创建ServiceMethod的代码中有一行代码:callAdapter=createCallAdapter(),这里创建了callAdapter。这段代码里面,是根据方法的返回类型和注解来寻找对应的CallAdapter,在哪里找呢?转到Retrofit对象的adapterFactories集合。我们在创建Retrofit的时候,可以调用addCallAdapter将CallAdapter添加到adapterFactories中。在前面的基本用法中,我们并没有添加任何CallAdapter,而是在adapterFactories中默认添加了一个ExecutorCallAdapterFactory,调用其get方法即可获取到CallAdapter对象。那么CallAdapter是做什么的呢?上面调用了adapt方法,就是把一个Call转换成另外一个类型。比如Retrofit和RxJava结合使用时,接口中的方法可以返回Observable,相当于适配器模式。默认获取一个Call对象,即ExecutorCallbackCall,代码如下:publicCallAdapter>get(TypereturnType,Annotation[]annotations,Retrofitretrofit){if(getRawType(returnType)!=Call.class){returnnull;}finalTyperesponseType=Utils.getCallResponseType(returnType);returnnewCallAdapter>(){@OverridepublicTyperesponseType(){returnresponseType;}@OverridepublicCalladapt(Callcall){returnnewExecutorCallbackCall<>(callbackExecutor,call);}};}这个ExecutorCallbackCall接受一个callbackExecutor(Android中默认是MainThreadExecutor,它将返回的数据传回主线程)和一个调用,即OkhttpCall。看下ExecutorCallbackCall部分代码:staticfinalclassExecutorCallbackCallimplementsCall{finalExecutorcallbackExecutor;finalCalldelegate;ExecutorCallbackCall(ExecutorcallbackExecutor,Calldelegate){this.callbackExecutor=callbackExecutor=;deleguenvodelegate@this.Overididegate}finalCallbackcallback){if(callback==null)thrownewNullPointerException("callback==null");delegate.enqueue(newCallback(){@OverridepublicvoidonResponse(Callcall,finalResponseresponse){callbackExecutor.execute(newRunnable(){@Overridepublicvoidrun(){if(delegate.isCanceled()){//EmulateOkHttp'sbehaviorofthrowing/deliveringanIOExceptiononcancellation.callback.onFailure(ExecutorCallbackCall.this,newIOException("Canceled"));}else{callback.onResponse(ExecutorCallbackCall.this,response);}}});}@OverridepublicvoidonFailure(Callcall,finalThrowablet){callbackExecutor.execute(newRunnable(){@Overridepublicvoidrun(){callback.onFailure(ExecutorCallbackCall.this,t);}});}});}enqueue方法中调用了OkHttpCall的enqueue,所以这个相当于静态代理模式OkHttpCall中的enqueue其实就是调用了原来OkHttp中的enqueue,这里才是真正发送网络请求的地方。部分代码如下:@Overridepublicvoidenqueue(finalCallbackcallback){if(callback==null)thrownewNullPointerException("callback==null");//调用http3.Callcall;Throwablefailure;Throwablefailure;synchronized(this){if(executed)thrownewIllegalStateException("Alreadyexecuted.");executed=true;//部分代码省略...call=rawCall;//enqueue异步执行call.enqueue(newokhttp3.Callback(){@OverridepublicvoidonResponse(okhttp3.Callcall,okhttp3.ResponserawResponse)throwsIOException{Responseresponse;try{//ConverterFactory会被用来解析数据并将response转换为对应的Java类型response=parseResponse(rawResponse);}catch(Throwablee){callFailure(e);return;}callSuccess(response);}@OverridepublicvoidonFailure(okhttp3.Callcall,IOExceptione){try{callback.onFailure(OkHttpCall.this,e);}catch(Throwablet){t.printStackTrace();}}privatevoidcallFailure(Throwablee){try{callback.onFailure(OkHttpCall.this,e);}catch(Throwablet){t.printStackTrace();}}privatevoidcallSuccess(Responseresponse){try{callback.onResponse(OkHttpCall.this,response);}catch(Throwablet){t.printStackTrace();}}});OkHttp获取到数据后,解析数据并回调回调响应方式在一次网络请求中完成。Retrofit整个框架的代码并不算多,也比较容易阅读。主要是通过动态代理将Java接口解析成响应网络请求,然后交给OkHttp执行。并且可以适配不同的CallAdapter,可以方便的和RxJava结合使用。