android Retrofit简单使用及源码分析
简介
Retrofit是Square公司开发的一款针对Android网络请求的框架,Retrofit2底层基于OkHttp实现的。
在gradle中添加
compile 'com.squareup.retrofit2:retrofit:2.3.0' compile 'com.squareup.retrofit2:converter-gson:2.3.0'
实现简单的POST请求
- 首先创建业务接口,代码如下
public interface LoginService { @POST("user/auth") Call login(@Query("username") String username, @Query("password") String password);}
这里对几种类型的注解做下说明:
@GET 和@POST分别对应get和post请求
@Query代表请求参数,另外还有@Body,@Field,@Part,@Path,@Header等注解
2.完成LoginService的配置
Retrofit retrofit = new Retrofit.Builder() .baseUrl(baseUrl) .addConverterFactory(GsonConverterFactory.create()) .build(); LoginService loginService = retrofit.create(LoginService.class);
3.调用接口方法,完成请求
Call<User> call = loginService.login("nanguangtailang","123"); call.enqueue(new Callback<User>() { @Override public void onResponse(Call<User> call, Response<User> response) { Log.d("d",response.body().toString()); } @Override public void onFailure(Call<User> call, Throwable t) { Log.d("f",t.getMessage()); } });
到这里我们的第一次简单使用Retrofit之旅已经结束了,接下来我们看看Retrofit关键实现的源码(主要关注第二步中出现的类和方法)
在创建Retrofit实例使用了builder模式,Builder是Retrofit中的一个嵌套类,代码如下
public static final class Builder { private final Platform platform; private @Nullable okhttp3.Call.Factory callFactory; private HttpUrl baseUrl; private final List converterFactories = new ArrayList<>(); private final List adapterFactories = new ArrayList<>(); private @Nullable Executor callbackExecutor; private boolean validateEagerly; Builder(Platform platform) { this.platform = platform; // Add the built-in converter factory first. This prevents overriding its behavior but also // ensures correct behavior when using converters that consume all types. converterFactories.add(new BuiltInConverters()); } public Builder() { this(Platform.get()); }
可以看到这个类中的几个重要属性 Platform、okhttp3.Call.Factory、List< Converter.Factory >、List< CallAdapter.Factory > 、Executor
platform 代表我们目前使用的平台,Android、iOS等 ,okhttp3.Call.Factory 是我们传入的 okhttpClient,作用是代理Retrofit发出http请求
接下来我们看看
LoginService loginService = retrofit.create(LoginService.class);
这行代码执行时发生了什么
这是create()方法的内部实现
public T create(final Class 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, @Nullable Object[] args) throws Throwable { // If the method is a method from Object then defer to normal invocation. if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } if (platform.isDefaultMethod(method)) { return platform.invokeDefaultMethod(method, service, proxy, args); } ServiceMethod
这个方法中最重要的就是
Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },new InvocationHandler() {···})
这里就必须要提到java的动态代理机制了,可以通过代理模式来理解java的动态代理
代理模式是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个真实对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理
关于动态代理的具体细节可以参考Java动态代理的使用及原理分析
现在我们知道了实际执行的代码是
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { // If the method is a method from Object then defer to normal invocation. if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } if (platform.isDefaultMethod(method)) { return platform.invokeDefaultMethod(method, service, proxy, args); } ServiceMethod<Object, Object> serviceMethod = (ServiceMethod) loadServiceMethod(method); OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.callAdapter.adapt(okHttpCall); }
如果我们传入的参数没有错误的话,应该会执行到此方法的最后三行
倒数第二行获得了OkHttpCall类,最后一行将okHttpCall装饰成ExecutorCallbackCall类,然后再返回给调用程序。
其实看到这里我们已经能够发现请求已经被委托给了OkHttpCall,我们在看下OkHttpCall类的内部实现
final class OkHttpCall implements Call { private final ServiceMethod serviceMethod; private final @Nullable Object[] args; private volatile boolean canceled; @GuardedBy("this") private @Nullable okhttp3.Call rawCall; @GuardedBy("this") private @Nullable Throwable creationFailure; // Either a RuntimeException or IOException. @GuardedBy("this") private boolean executed; OkHttpCall(ServiceMethod serviceMethod, @Nullable Object[] args) { this.serviceMethod = serviceMethod; this.args = args; } @SuppressWarnings("CloneDoesntCallSuperClone") // We are a final type & this saves clearing state. @Override public OkHttpCall clone() { return new OkHttpCall<>(serviceMethod, args); } @Override public synchronized Request request() { okhttp3.Call call = rawCall; if (call != null) { return call.request(); } if (creationFailure != null) { if (creationFailure instanceof IOException) { throw new RuntimeException("Unable to create request.", creationFailure); } else { throw (RuntimeException) creationFailure; } } try { return (rawCall = createRawCall()).request(); } catch (RuntimeException e) { creationFailure = e; throw e; } catch (IOException e) { creationFailure = e; throw new RuntimeException("Unable to create request.", e); } } @Override public void enqueue(final Callback callback) { checkNotNull(callback, "callback == null"); okhttp3.Call call; Throwable failure; synchronized (this) { if (executed) throw new IllegalStateException("Already executed."); executed = true; call = rawCall; failure = creationFailure; if (call == null && failure == null) { try { call = rawCall = createRawCall(); } catch (Throwable t) { failure = creationFailure = t; } } } if (failure != null) { callback.onFailure(this, failure); return; } if (canceled) { call.cancel(); } call.enqueue(new okhttp3.Callback() { @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) throws IOException { Response response; try { response = parseResponse(rawResponse); } catch (Throwable e) { callFailure(e); return; } callSuccess(response); } @Override public void onFailure(okhttp3.Call call, IOException e) { try { callback.onFailure(OkHttpCall.this, e); } catch (Throwable t) { t.printStackTrace(); } } 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(); } } }); } @Override public synchronized boolean isExecuted() { return executed; } @Override public Response execute() throws IOException { okhttp3.Call call; synchronized (this) { if (executed) throw new IllegalStateException("Already executed."); executed = true; if (creationFailure != null) { if (creationFailure instanceof IOException) { throw (IOException) creationFailure; } else { throw (RuntimeException) creationFailure; } } call = rawCall; if (call == null) { try { call = rawCall = createRawCall(); } catch (IOException | RuntimeException e) { creationFailure = e; throw e; } } } if (canceled) { call.cancel(); } return parseResponse(call.execute()); } private okhttp3.Call createRawCall() throws IOException { Request request = serviceMethod.toRequest(args); okhttp3.Call call = serviceMethod.callFactory.newCall(request); if (call == null) { throw new NullPointerException("Call.Factory returned null."); } return call; } Response parseResponse(okhttp3.Response rawResponse) throws IOException { ResponseBody rawBody = rawResponse.body(); // Remove the body's source (the only stateful object) so we can pass the response along. rawResponse = rawResponse.newBuilder() .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength())) .build(); int code = rawResponse.code(); if (code < 200 || code >= 300) { try { // Buffer the entire body to avoid future I/O. ResponseBody bufferedBody = Utils.buffer(rawBody); return Response.error(bufferedBody, rawResponse); } finally { rawBody.close(); } } if (code == 204 || code == 205) { rawBody.close(); return Response.success(null, rawResponse); } ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody); try { T body = serviceMethod.toResponse(catchingBody); return Response.success(body, rawResponse); } catch (RuntimeException e) { // If the underlying source threw an exception, propagate that rather than indicating it was // a runtime exception. catchingBody.throwIfCaught(); throw e; } } public void cancel() { canceled = true; okhttp3.Call call; synchronized (this) { call = rawCall; } if (call != null) { call.cancel(); } } @Override public boolean isCanceled() { if (canceled) { return true; } synchronized (this) { return rawCall != null && rawCall.isCanceled(); } } static final class NoContentResponseBody extends ResponseBody { private final MediaType contentType; private final long contentLength; NoContentResponseBody(MediaType contentType, long contentLength) { this.contentType = contentType; this.contentLength = contentLength; } @Override public MediaType contentType() { return contentType; } @Override public long contentLength() { return contentLength; } @Override public BufferedSource source() { throw new IllegalStateException("Cannot read raw response body of a converted body."); } } static final class ExceptionCatchingRequestBody extends ResponseBody { private final ResponseBody delegate; IOException thrownException; ExceptionCatchingRequestBody(ResponseBody delegate) { this.delegate = delegate; } @Override public MediaType contentType() { return delegate.contentType(); } @Override public long contentLength() { return delegate.contentLength(); } @Override public BufferedSource source() { return Okio.buffer(new ForwardingSource(delegate.source()) { @Override public long read(Buffer sink, long byteCount) throws IOException { try { return super.read(sink, byteCount); } catch (IOException e) { thrownException = e; throw e; } } }); } @Override public void close() { delegate.close(); } void throwIfCaught() throws IOException { if (thrownException != null) { throw thrownException; } } }}
其实OkHttpCall就是封装了okHttp的实现,所以retrofit最终的请求时由okhttp发起的。
更多相关文章
- Android(安卓)Json解析方法
- bitmap设置图片尺寸缩小,避免内存溢出/OutOfMemoryError的优化方
- Android反射机制实现与原理
- android ListView显示网络图片
- Android(安卓)Handler 用法解析
- Android面试常客之Handler全解
- Android(安卓)ProGuard技术详解
- 实现TabWidget选项卡按钮在屏幕下方
- Android(安卓)通过反射调用获取内置存储和外置sd卡根路径(适用于