Android今年面试什么?来自百度篇
Posted 初一十五啊
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android今年面试什么?来自百度篇相关的知识,希望对你有一定的参考价值。
前言
虽说2022年只剩下整整2个月了,但是今年的局势不是很焦灼,疫情原因,行情问题,导致很多小伙伴吐槽找工作好难啊。
今天来分享一下关于百度会问那些技术点,提前做好公开事半功倍。😁
关注公众号:初一十五a
解锁 《Android十三大板块文档》,让学习更贴近未来实战。已形成PDF版
内容如下:
1.2022最新Android11位大厂面试专题,128道附答案
2.音视频大合集,从初中高到面试应有尽有
3.Android车载应用大合集,从零开始一起学
4.性能优化大合集,告别优化烦恼
5.Framework大合集,从里到外分析的明明白白
6.Flutter大合集,进阶Flutter高级工程师
7.compose大合集,拥抱新技术
8.Jetpack大合集,全家桶一次吃个够
9.架构大合集,轻松应对工作需求
10.Android基础篇大合集,根基稳固高楼平地起
11.Flutter番外篇:Flutter面试+Flutter项目实战+Flutter电子书
12.高级Android组件化强化实战
13.十二模块之补充部分:其他Android十一大知识体系
整理不易,关注一下吧。开始进入正题,ღ( ´・ᴗ・` ) 🤔
一丶百度篇
1.关于OKhttp
和Retrofit
Retrofit
①基本使用流程
定义HTTP API,用于描述请求
public interface GitHubService
@GET("users/user/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
创建Retrofit并生成API的实现
(注意: 方法上面的注解表示请求的接口部分,返回类型是请求的返回值类型,方法的参数即是请求的参数)
// 1.Retrofit构建过程
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
// 2.创建网络请求接口类实例过程
GitHubService service = retrofit.create(GitHubService.class);
调用API方法,生成Call,执行请求
// 3.生成并执行请求过程
Call<List<Repo>> repos = service.listRepos("octocat");
repos.execute() or repos.enqueue()
Retrofit的基本使用流程很简洁,但是简洁并不代表简单,Retrofit为了实现这种简洁的使用流程,内部使用了优秀的架构设计和大量的设计模式,在分析过Retrofit最新版的源码和大量优秀的Retrofit源码分析文章后发现,要想真正理解Retrofit内部的核心源码流程和设计思想,首先,需要对这九大设计模式有一定的了解,如下:
-
Retrofit构建过程
建造者模式、工厂方法模式 -
创建网络请求接口实例过程
外观模式、代理模式、单例模式、策略模式、装饰模式(建造者模式) -
生成并执行请求过程
适配器模式(代理模式、装饰模式)
其次,需要对OKHttp源码有一定的了解。让我们按以上流程去深入Retrofit源码内部,领悟它带给我们的设计之美。
②Retrofit构建过程
Retrofit核心对象解析
首先Retrofit中有一个全局变量非常关键,在V2.5之前的版本,使用的是LinkedHashMap()
,它是一个网络请求配置对象,是由网络请求接口中方法注解进行解析后得到的。
public final class Retrofit
// 网络请求配置对象,存储网络请求相关的配置,如网络请求的方法、数据转换器、网络请求适配器、网络请求工厂、基地址等
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
Retrofit使用了建造者模式通过内部类Builder类建立一个Retrofit实例,如下:
public static final class Builder
// 平台类型对象(Platform -> android)
private final Platform platform;
// 网络请求工厂,默认使用OkHttpCall(工厂方法模式)
private @Nullable okhttp3.Call.Factory callFactory;
// 网络请求的url地址
private @Nullable HttpUrl baseUrl;
// 数据转换器工厂的集合
private final List<Converter.Factory> converterFactories = new ArrayList<>();
// 网络请求适配器工厂的集合,默认是ExecutorCallAdapterFactory
private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
// 回调方法执行器,在 Android 上默认是封装了 handler 的 MainThreadExecutor, 默认作用是:切换线程(子线程 -> 主线程)
private @Nullable Executor callbackExecutor;
// 一个开关,为true则会缓存创建的ServiceMethod
private boolean validateEagerly;
Builder内部构造
下面看看Builder内部构造做了什么。
public static final class Builder
...
Builder(Platform platform)
this.platform = platform;
public Builder()
this(Platform.get());
...
class Platform
private static final Platform PLATFORM = findPlatform();
static Platform get()
return PLATFORM;
private static Platform findPlatform()
try
// 使用JVM加载类的方式判断是否是Android平台
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0)
return new Android();
catch (ClassNotFoundException ignored)
try
// 同时支持Java平台
Class.forName("java.util.Optional");
return new Java8();
catch (ClassNotFoundException ignored)
return new Platform();
static class Android extends Platform
...
@Override public Executor defaultCallbackExecutor()
//切换线程(子线程 -> 主线程)
return new MainThreadExecutor();
// 创建默认的网络请求适配器工厂,如果是Android7.0或Java8上,则使
// 用了并发包中的CompletableFuture保证了回调的同步
// 在Retrofit中提供了四种CallAdapterFactory(策略模式):
// ExecutorCallAdapterFactory(默认)、GuavaCallAdapterFactory、
// va8CallAdapterFactory、RxJavaCallAdapterFactory
@Override List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
@Nullable Executor callbackExecutor)
if (callbackExecutor == null) throw new AssertionError();
ExecutorCallAdapterFactory executorFactory = new ExecutorCallAdapterFactory(callbackExecutor);
return Build.VERSION.SDK_INT >= 24
? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
: singletonList(executorFactory);
...
@Override List<? extends Converter.Factory> defaultConverterFactories()
return Build.VERSION.SDK_INT >= 24
? singletonList(OptionalConverterFactory.INSTANCE)
: Collections.<Converter.Factory>emptyList();
...
static class MainThreadExecutor implements Executor
// 获取Android 主线程的Handler
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r)
// 在UI线程对网络请求返回数据处理
handler.post(r);
可以看到,在Builder内部构造时设置了默认Platform、callAdapterFactories和callbackExecutor。
添加baseUrl
很简单,就是将String类型的url转换为OkHttp的HttpUrl过程如下:
/**
* Set the API base URL.
*
* @see #baseUrl(HttpUrl)
*/
public Builder baseUrl(String baseUrl)
checkNotNull(baseUrl, "baseUrl == null");
return baseUrl(HttpUrl.get(baseUrl));
public Builder baseUrl(HttpUrl baseUrl)
checkNotNull(baseUrl, "baseUrl == null");
List<String> pathSegments = baseUrl.pathSegments();
if (!"".equals(pathSegments.get(pathSegments.size() - 1)))
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
this.baseUrl = baseUrl;
return this;
添加GsonConverterFactory
首先,看到GsonConverterFactory.creat()的源码。
public final class GsonConverterFactory extends Converter.Factory
public static GsonConverterFactory create()
return create(new Gson());
public static GsonConverterFactory create(Gson gson)
if (gson == null) throw new NullPointerException("gson == null");
return new GsonConverterFactory(gson);
private final Gson gson;
// 创建了一个含有Gson对象实例的GsonConverterFactory
private GsonConverterFactory(Gson gson)
this.gson = gson;
然后,看看addConverterFactory()方法内部。
public Builder addConverterFactory(Converter.Factory factory)
converterFactories.add(checkNotNull(factory, "factory null"));
return this;
可知,这一步是将一个含有Gson对象实例的GsonConverterFactory放入到了数据转换器工厂converterFactories里。
build过程
public Retrofit build()
if (baseUrl == null)
throw new IllegalStateException("Base URL required.");
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null)
// 默认使用okhttp
callFactory = new OkHttpClient();
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null)
// Android默认的callbackExecutor
callbackExecutor = platform.defaultCallbackExecutor();
// Make a defensive copy of the adapters and add the defaultCall adapter.
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
// 添加默认适配器工厂在集合尾部
callAdapterFactories.addAll(platform.defaultCallAdapterFactorisca llbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters thatconsumeall types.
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories();
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
可以看到,最终我们在Builder类中看到的6大核心对象都已经配置到Retrofit对象中了
③创建网络请求接口实例过程
retrofit.create()使用了外观模式和代理模式创建了网络请求的接口实例,我们分析下create方法。
public <T> T create(final Class<T> service)
Utils.validateServiceInterface(service);
if (validateEagerly)
// 判断是否需要提前缓存ServiceMethod对象
eagerlyValidateMethods(service);
// 使用动态代理拿到请求接口所有注解配置后,创建网络请求接口实例
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] service ,
new InvocationHandler()
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@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);
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
);
private void eagerlyValidateMethods(Class<?> service)
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods())
if (!platform.isDefaultMethod(method))
loadServiceMethod(method);
继续看看loadServiceMethod的内部流程
ServiceMethod<?> loadServiceMethod(Method method)
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache)
result = serviceMethodCache.get(method);
if (result == null)
// 解析注解配置得到了ServiceMethod
result = ServiceMethod.parseAnnotations(this, method);
// 可以看到,最终加入到ConcurrentHashMap缓存中
serviceMethodCache.put(method, result);
return result;
abstract class ServiceMethod<T>
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method)
// 通过RequestFactory解析注解配置(工厂模式、内部使用了建造者模式)
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType))
throw methodError(method,
"Method return type must not include a type variable or wildcard: %s", returnType);
if (returnType == void.class)
throw methodError(method, "Service methods cannot return void.");
// 最终是通过HttpServiceMethod构建的请求方法
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
abstract T invoke(Object[] args);
请求构造核心流程
根据RequestFactory#Builder构造方法和parseAnnotations方法的源码,可知的它的作用就是用来解析注解配置的。
Builder(Retrofit retrofit, Method method)
this.retrofit = retrofit;
this.method = method;
// 获取网络请求接口方法里的注释
this.methodAnnotations = method.getAnnotations();
// 获取网络请求接口方法里的参数类型
this.parameterTypes = method.getGenericParameterTypes();
// 获取网络请求接口方法里的注解内容
this.parameterAnnotationsArray = method.getParameterAnnotations();
接着看HttpServiceMethod.parseAnnotations()的内部流程。
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory)
//1.根据网络请求接口方法的返回值和注解类型,
// 从Retrofit对象中获取对应的网络请求适配器
CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit,method);
// 得到响应类型
Type responseType = callAdapter.responseType();
...
//2.根据网络请求接口方法的返回值和注解类型从Retrofit对象中获取对应的数据转换器
Converter<ResponseBody, ResponseT>responseConverter =
createResponseConverter(retrofit,method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
return newHttpServiceMethod<>(requestFactory, callFactory, callAdapter,responseConverter);
createCallAdapter(retrofit, method)
private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
Retrofit retrofit, Method method)
// 获取网络请求接口里方法的返回值类型
Type returnType = method.getGenericReturnType();
// 获取网络请求接口接口里的注解
Annotation[] annotations = method.getAnnotations();
try
//noinspection unchecked
return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
catch (RuntimeException e) // Wide exception range because factories are user code.
throw methodError(method, e, "Unable to create call adapter for %s", returnType);
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations)
return nextCallAdapter(null, returnType, annotations);
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations)
...
int start = callAdapterFactories.indexOf(skipPast) + 1;
// 遍历 CallAdapter.Factory 集合寻找合适的工厂
for (int i = start, count = callAdapterFactories.size(); i <count; i++)
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null)
return adapter;
createResponseConverter(Retrofit retrofit, Method method, Type responseType)
private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(
Retrofit retrofit, Method method, Type responseType)
Annotation[] annotations = method.getAnnotations();
try
return retrofit.responseBodyConverter(responseType,annotations);
catch (RuntimeException e) // Wide exception range because factories are user code.
throw methodError(method, e, "Unable to create converter for%s", responseType);
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations)
return nextResponseBodyConverter(null, type, annotations);
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations)
...
int start = converterFactories.indexOf(skipPast) + 1;
// 遍历 Converter.Factory 集合并寻找合适的工厂, 这里是GsonResponseBodyConverter
for (int i = start, count = converterFactories.size(); i < count; i++)
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null)
//noinspection unchecked
return (Converter<ResponseBody, T>) converter;
执行HttpServiceMethod的invoke方法
@Override ReturnT invoke(Object[] args)
return callAdapter.adapt(
new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
最终在adapt中创建了一个ExecutorCallbackCall对象,它是一个装饰者,而在它内部真正去执行网络请求的还是OkHttpCall。
④创建网络请求接口类实例并执行请求过程
service.listRepos()
1、Call<List<Repo>> repos = service.listRepos("octocat");
service对象是动态代理对象Proxy.newProxyInstance(),当调用getCall()时会被 它拦截,然后调用自身的InvocationHandler#invoke(),得到最终的Call对象。
同步执行流程 repos.execute()
@Override public Response<T> 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 if (creationFailure instanceof RuntimeException)
throw (RuntimeException) creationFailure;
else
throw (Error) creationFailure;
call = rawCall;
if (call == null)
try
// 创建一个OkHttp的Request对象请求
call = rawCall = createRawCall();
catch (IOException | RuntimeException | Error e)
throwIfFatal(e); // Do not assign a fatal error to creationFailure.
creationFailure = e;
throw e;
if (canceled)
call.cancel();
// 调用OkHttpCall的execute()发送网络请求(同步),
// 并解析网络请求返回的数据
return parseResponse(call.execute());
private okhttp3.Call createRawCall() throws IOException
// 创建 一个okhttp3.Request
okhttp3.Call call =
callFactory.newCall(requestFactory.create(args));
if (call == null)
throw new NullPointerException("Call.Factory returned null.");
return call;
Response<T> 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);
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try
// 将响应体转为Java对象
T body = responseConverter.convert(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;
异步请求流程 reponse.enqueque
@Override
public void enqueue(final Callback<T> callback)
// 使用静态代理 delegate进行异步请求
delegate.enqueue(new Callback<T>()
@Override
public void onResponse(Call<T> call, finalResponse<T>response)
// 线程切换,在主线程显示结果
callbackExecutor.execute(new Runnable()
@Override
public void run()
if (delegate.isCanceled())
callback.onFailure(ExecutorCallbackCall.this, newIOException("Canceled"));
else
callback.onResponse(ExecutorCallbackCall.this,respons);
);
@Override
public void onFailure(Call<T> call, final Throwable t)
callbackExecutor.execute(new Runnable()
@Override public void run()
callback.onFailure(ExecutorCallbackCall.this, t);
);
);
看看 delegate.enqueue 内部流程。
@Override
public void enqueue(final Callback<T> callback)
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
// 创建OkHttp的Request对象,再封装成OkHttp.call
// 方法同发送同步请求,此处上面已分析
call = rawCall = createRawCall();
catch (Throwable t)
failure = creationFailure = t;
@Override public void enqueue(final Callback<T> callback)
checkNotNull(callback, "callback == null");
okhttp3.Call call;
Throwable failure;
...
call.enqueue(new okhttp3.Callback()
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
Response<T> response;
try
// 此处上面已分析
response = parseResponse(rawResponse);
catch (Throwable e)
throwIfFatal(e);
callFailure(e);
return;
try
callback.onResponse(OkHttpCall.this, response);
catch (Throwable t)
t.printStackTrace();
@Override public void onFailure(okhttp3.Call call, IOException e)
callFailure(e);
private void callFailure(Throwable e)
try
callback.onFailure(OkHttpCall.this, e);
catch (Throwable t)
t.printStackTrace();
);
⑤Retrofit源码流程图
建议大家自己主动配合着Retrofit最新版的源码一步步去彻底地认识它,只有这样,你才能看到它真实的内心,附上一张Retrofit源码流程图,要注意的是,这是V2.5之前版本的流程,但是,在看完上面的源码分析后,我们知道,主体流程是没有变化的。
从本质上来说,Retrofit虽然只是一个RESTful 的HTTP 网络请求框架的封装库。但是,它内部通过 大量的设计模式 封装了 OkHttp,让使用者感到它非常简洁、易懂。它内部主要是用动态代理的方式,动态将网络请求接口的注解解析成HTTP请求,最后执行请求的过程。
OKhttp
①OKHttp网络框架
OKHttp内部的大致请求流程图如下所示:
如下为使用OKHttp进行Get请求的步骤:
//1.新建OKHttpClient客户端
OkHttpClient client = new OkHttpClient();
//新建一个Request对象
Request request = new Request.Builder()
.url(url)
.build();
//2.Response为OKHttp中的响应
Response response = client.newCall(request).execute();
新建OKHttpClient客户端
OkHttpClient client = new OkHttpClient();
public OkHttpClient()
this(new Builder());
OkHttpClient(Builder builder)
....
可以看到,OkHttpClient使用了建造者模式,Builder里面的可配置参数如下:
public static final class Builder
Dispatcher dispatcher;// 分发器
@Nullable Proxy proxy;
List<Protocol> protocols;
List<ConnectionSpec> connectionSpecs;// 传输层版本和连接协议
final List<Interceptor> interceptors = new ArrayList<>();// 拦截器
final List<Interceptor> networkInterceptors = new ArrayList<>();
EventListener.Factory eventListenerFactory;
ProxySelector proxySelector;
CookieJar cookieJar;
@Nullable Cache cache;
@Nullable InternalCache internalCache;// 内部缓存
SocketFactory socketFactory;
@Nullable SSLSocketFactory sslSocketFactory;// 安全套接层socket 工厂,用于HTTPS
@Nullable CertificateChainCleaner certificateChainCleaner;// 验证确认响应证书 适用 HTTPS 请求连接的主机名。
HostnameVerifier hostnameVerifier;// 验证确认响应证书 适用 HTTPS 请求连接的主机名。
CertificatePinner certificatePinner;// 证书锁定,使用CertificatePinner来约束哪些认证机构被信任。
Authenticator proxyAuthenticator;// 代理身份验证
Authenticator authenticator;// 身份验证
ConnectionPool connectionPool;// 连接池
Dns dns;
boolean followSslRedirects; // 安全套接层重定向
boolean followRedirects;// 本地重定向
boolean retryOnConnectionFailure;// 重试连接失败
int callTimeout;
int connectTimeout;
int readTimeout;
int writeTimeout;
int pingInterval;
// 这里是默认配置的构建参数
public Builder()
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
...
// 这里传入自己配置的构建参数
Builder(OkHttpClient okHttpClient)
this.dispatcher = okHttpClient.dispatcher;
this.proxy = okHttpClient.proxy;
this.protocols = okHttpClient.protocols;
this.connectionSpecs = okHttpClient.connectionSpecs;
this.interceptors.addAll(okHttpClient.interceptors);
this.networkInterceptors.addAll(okHttpClient.networkInterceptors);
...
同步请求流程
Response response = client.newCall(request).execute();
/**
* Prepares the @code request to be executed at some point in the future.
*/
@Override public Call newCall(Request request)
return RealCall.newRealCall(this, request, false /* for web socket */);
// RealCall为真正的请求执行者
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket)
// Safely publish the Call instance to the EventListener.
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.eventListener = client.eventListenerFactory().create(call);
return call;
@Override public Response execute() throws IOException
synchronized (this)
// 每个Call只能执行一次
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
captureCallStackTrace();
timeout.enter();
eventListener.callStart(this);
try
// 通知dispatcher已经进入执行状态
client.dispatcher().executed(this);
// 通过一系列的拦截器请求处理和响应处理得到最终的返回结果
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
catch (IOException e)
e = timeoutExit(e);
eventListener.callFailed(this, e);
throw e;
finally
// 通知 dispatcher 自己已经执行完毕
client.dispatcher().finished(this);
Response getResponseWithInterceptorChain() throws IOException
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
// 在配置 OkHttpClient 时设置的 interceptors;
interceptors.addAll(client.interceptors());
// 负责失败重试以及重定向
interceptors.add(retryAndFollowUpInterceptor);
// 请求时,对必要的Header进行一些添加,接收响应时,移除必要的Header
interceptors.add(new BridgeInterceptor(client.cookieJar()));
// 负责读取缓存直接返回、更新缓存
interceptors.add(new CacheInterceptor(client.internalCache()));
// 负责和服务器建立连接
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket)
// 配置 OkHttpClient 时设置的 networkInterceptors
interceptors.addAll(client.networkInterceptors());
// 负责向服务器发送请求数据、从服务器读取响应数据
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
// 使用责任链模式开启链式调用
return chain.proceed(originalRequest);
// StreamAllocation 对象,它相当于一个管理类,维护了服务器连接、并发流
// 和请求之间的关系,该类还会初始化一个 Socket 连接对象,获取输入/输出流对象。
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException
...
// Call the next interceptor in the chain.
// 实例化下一个拦截器对应的RealIterceptorChain对象
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
// 得到当前的拦截器
Interceptor interceptor = interceptors.get(index);
// 调用当前拦截器的intercept()方法,并将下一个拦截器的RealIterceptorChain对象传递下去,最后得到响应
Response response = interceptor.intercept(next);
...
return response;
异步请求流程
Request request = new Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.build();
client.newCall(request).enqueue(new Callback()
@Override
public void onFailure(Call call, IOException e)
e.printStackTrace();
@Override
public void onResponse(Call call, Response response) throws IOException
...
void enqueue(AsyncCall call)
synchronized (this)
readyAsyncCalls.add(call);
promoteAndExecute();
// 正在准备中的异步请求队列
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
// 运行中的异步请求
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
// 同步请求
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
// Promotes eligible calls from @link #readyAsyncCalls to @link #runningAsyncCalls and runs
// them on the executor service. Must not be called with synchronization because executing calls
// can call into user code.
private boolean promoteAndExecute()
assert (!Thread.holdsLock(this));
List<AsyncCall> executableCalls = new ArrayList<>();
boolean isRunning;
synchronized (this)
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); )
AsyncCall asyncCall = i.next();
// 如果其中的runningAsynCalls不满,且call占用的host小于最大数量,则将call加入到runningAsyncCalls中执行,
// 同时利用线程池执行call;否者将call加入到readyAsyncCalls中。
if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; // Host max capacity.
i.remove();
executableCalls.add(asyncCall);
runningAsyncCalls.add(asyncCall);
isRunning = runningCallsCount() > 0;
for (int i = 0, size = executableCalls.size(); i < size; i++)
AsyncCall asyncCall = executableCalls.get(i);
asyncCall.executeOn(executorService());
return isRunning;
最后,我们在看看AsynCall的代码。
final class AsyncCall extends NamedRunnable
private final Callback responseCallback;
AsyncCall(Callback responseCallback)
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
String host()
return originalRequest.url().host();
Request request()
return originalRequest;
RealCall get()
return RealCall.this;
/**
* Attempt to enqueue this async call on @code executorService. This will attempt to clean up
* if the executor has been shut down by reporting the call as failed.
*/
void executeOn(ExecutorService executorService)
assert (!Thread.holdsLock(client.dispatcher()));
boolean success = false;
try
executorService.execute(this);
success = true;
catch (RejectedExecutionException e)
InterruptedIOException ioException = new InterruptedIOException("executor rejected");
ioException.initCause(e);
eventListener.callFailed(RealCall.this, ioException);
responseCallback.onFailure(RealCall.this, ioException);
finally
if (!success)
client.dispatcher().finished(this); // This call is no longer running!
@Override protected void execute()
boolean signalledCallback = false;
timeout.enter();
try
// 跟同步执行一样,最后都会调用到这里
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled())
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
else
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
catch (IOException e)
e = timeoutExit(e);
if (signalledCallback)
// Do not signal the callback twice!
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
else
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);
finally
client.dispatcher().finished(this);
从上面的源码可以知道,拦截链的处理OKHttp帮我们默认做了五步拦截处理,其中RetryAndFollowUpInterceptor、BridgeInterceptor、CallServerInterceptor内部的源码很简洁易懂,此处不再多说。
网络请求缓存处理之CacheInterceptor
@Override public Response intercept(Chain chain) throws IOException
// 根据request得到cache中缓存的response
Response cacheCandidate = cache != null
? cache.get(chain.request())
: null;
long now = System.currentTimeMillis();
// request判断缓存的策略,是否要使用了网络,缓存或两者都使用
CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
Request networkRequest = strategy.networkRequest;
Response cacheResponse = strategy.cacheResponse;
if (cache != null)
cache.trackResponse(strategy);
if (cacheCandidate != null && cacheResponse == null)
closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
// If we're forbidden from using the network and the cache is insufficient, fail.
if (networkRequest == null && cacheResponse == null)
return new Response.Builder()
.request(chain.request())
.protocol(Protocol.HTTP_1_1)
.code(504)
.message("Unsatisfiable Request (only-if-cached)")
.body(Util.EMPTY_RESPONSE)
.sentRequestAtMillis(-1L)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
// If we don't need the network, we're done.
if (networkRequest == null)
return cacheResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.build();
Response networkResponse = null;
try
// 调用下一个拦截器,决定从网络上来得到response
networkResponse = chain.proceed(networkRequest);
finally
// If we're crashing on I/O or otherwise, don't leak the cache body.
if (networkResponse == null && cacheCandidate != null)
closeQuietly(cacheCandidate.body());
// If we have a cache response too, then we're doing a conditional get.
// 如果本地已经存在cacheResponse,那么让它和网络得到的networkResponse做比较,决定是否来更新缓存的cacheResponse
if (cacheResponse != null)
if (networkResponse.code() == HTTP_NOT_MODIFIED)
Response response = cacheResponse.newBuilder()
.headers(combine(cacheResponse.headers(), networkResponse.headers()))
.sentRequestAtMillis(networkResponse.sentRequestAtMillis())
.receivedResponseAtMillis(networkResponse.receivedResponseAtMillis())
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
networkResponse.body().close();
// Update the cache after combining headers but before stripping the
// Content-Encoding header (as performed by initContentStream()).
cache.trackConditionalCacheHit();
cache.update(cacheResponse, response);
return response;
else
closeQuietly(cacheResponse.body());
Response response = networkResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
if (cache != null)
if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest))
// Offer this request to the cache.
// 缓存未经缓存过的response
CacheRequest cacheRequest = cache.put(response);
return cacheWritingResponse(cacheRequest, response);
if (HttpMethod.invalidatesCache(networkRequest.method()))
try
cache.remove(networkRequest);
catch (IOException ignored)
// The cache cannot be written.
return response;
缓存拦截器会根据请求的信息和缓存的响应的信息来判断是否存在缓存可用,如果有可以使用的缓存,那么就返回该缓存给用户,否则就继续使用责任链模式来从服务器中获取响应。当获取到响应的时候,又会把响应缓存到磁盘上面。
ConnectInterceptor之连接池
@Override public Response intercept(Chain chain) throws IOException
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Request request = realChain.request();
StreamAllocation streamAllocation = realChain.streamAllocation();
// We need the network to satisfy this request. Possibly for validating a conditional GET.
boolean doExtensiveHealthChecks = !request.method().equals("GET");
// HttpCodec是对 HTTP 协议操作的抽象,有两个实现:Http1Codec和Http2Codec,顾名思义,它们分别对应 HTTP/1.1 和 HTTP/2 版本的实现。在这个方法的内部实现连接池的复用处理
HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
RealConnection connection = streamAllocation.connection();
return realChain.proceed(request, streamAllocation, httpCodec, connection);
// Returns a connection to host a new stream. This // prefers the existing connection if it exists,
// then the pool, finally building a new connection.
// 调用 streamAllocation 的 newStream() 方法的时候,最终会经过一系列
// 的判断到达 StreamAllocation 中的 findConnection() 方法
private RealConnection findConnection(int connectTimeout, int readTimeout, int writeTimeout,
int pingIntervalMillis, boolean connectionRetryEnabled) throws IOException
...
// Attempt to use an already-allocated connection. We need to be careful here because our
// already-allocated connection may have been restricted from creating new streams.
// 尝试使用已分配的连接,已经分配的连接可能已经被限制创建新的流
releasedConnection = this.connection;
// 释放当前连接的资源,如果该连接已经被限制创建新的流,就返回一个Socket以关闭连接
toClose = releaseIfNoNewStreams();
if (this.connection != null)
// We had an already-allocated connection and it's good.
result = this.connection;
releasedConnection = null;
if (!reportedAcquired)
// If the connection was never reported acquired, don't report it as released!
// 如果该连接从未被标记为获得,不要标记为发布状态,reportedAcquired 通过 acquire() 方法修改
releasedConnection = null;
if (result == null)
// Attempt to get a connection from the pool.
// 尝试供连接池中获取一个连接
Internal.instance.get(connectionPool, address, this, null);
if (connection != null)
foundPooledConnection = true;
result = connection;
else
selectedRoute = route;
// 关闭连接
closeQuietly(toClose);
if (releasedConnection != null)
eventListener.connectionReleased(call, releasedConnection);
if (foundPooledConnection)
eventListener.connectionAcquired(call, result);
if (result != null)
// If we found an already-allocated or pooled connection, we're done.
// 如果已经从连接池中获取到了一个连接,就将其返回
return result;
// If we need a route selection, make one. This is a blocking operation.
boolean newRouteSelection = false;
if (selectedRoute == null && (routeSelection == null || !routeSelection.hasNext()))
newRouteSelection = true;
routeSelection = routeSelector.next();
synchronized (connectionPool)
if (canceled) throw new IOException("Canceled");
if (newRouteSelection)
// Now that we have a set of IP addresses, make another attempt at getting a connection from
// the pool. This could match due to connection coalescing.
// 根据一系列的 IP地址从连接池中获取一个链接
List<Route> routes = routeSelection.getAll();
for (int i = 0, size = routes.size(); i < size;i++)
Route route = routes.get(i);
// 从连接池中获取一个连接
Internal.instance.get(connectionPool, address, this, route);
if (connection != null)
foundPooledConnection = true;
result = connection;
this.route = route;
break;
if (!foundPooledConnection)
if (selectedRoute == null)
selectedRoute = routeSelection.next();
// Create a connection and assign it to this allocation immediately. This makes it possible
// for an asynchronous cancel() to interrupt the handshake we're about to do.
// 在连接池中如果没有该连接,则创建一个新的连接,并将其分配,这样我们就可以在握手之前进行终端
route = selectedRoute;
refusedStreamCount = 0;
result = new RealConnection(connectionPool, selectedRoute);
acquire(result, false);
// If we found a pooled connection on the 2nd time around, we're done.
if (foundPooledConnection)
// 如果我们在第二次的时候发现了一个池连接,那么我们就将其返回
eventListener.connectionAcquired(call, result);
return result;
// Do TCP + TLS handshakes. This is a blocking operation.
// 进行 TCP 和 TLS 握手
result.connect(connectTimeout, readTimeout, writeTimeout, pingIntervalMillis,
connectionRetryEnabled, call, eventListener);
routeDatabase().connected(result.route());
Socket socket = null;
synchronized (connectionPool)
reportedAcquired = true;
// Pool the connection.
// 将该连接放进连接池中
Internal.instance.put(connectionPool, result);
// If another multiplexed connection to the same address was created concurrently, then
// release this connection and acquire that one.
// 如果同时创建了另一个到同一地址的多路复用连接,释放这个连接并获取那个连接
if (result.isMultiplexed())
socket = Internal.instance.deduplicate(connectionPool, address, this);
result = connection;
closeQuietly(socket);
eventListener.connectionAcquired(call, result);
return result;
从以上的源码分析可知:
- 判断当前的连接是否可以使用:流是否已经被关闭,并且已经被限制创建新的流;
- 如果当前的连接无法使用,就从连接池中获取一个连接;
- 连接池中也没有发现可用的连接,创建一个新的连接,并进行握手,然后将其放到连接池中。
在从连接池中获取一个连接的时候,使用了 Internal 的 get() 方法。Internal 有一个静态的实例,会在 OkHttpClient 的静态代码快中被初始化。我们会在 Internal 的 get() 中调用连接池的 get() 方法来得到一个连接。并且,从中我们明白了连接复用的一个好处就是省去了进行 TCP 和 TLS 握手的一个过程。因为建立连接本身也是需要消耗一些时间的,连接被复用之后可以提升我们网络访问的效率。
接下来详细分析下ConnectionPool是如何实现连接管理的。
OkHttp 的缓存管理分成两个步骤,一边当我们创建了一个新的连接的时候,我们要把它放进缓存里面;另一边,我们还要来对缓存进行清理。在 ConnectionPool 中,当我们向连接池中缓存一个连接的时候,只要调用双端队列的 add() 方法,将其加入到双端队列即可,而清理连接缓存的操作则交给线程池来定时执行。
private final Deque<RealConnection> connections = new ArrayDeque<>();
void put(RealConnection connection)
assert (Thread.holdsLock(this));
if (!cleanupRunning)
cleanupRunning = true;
// 使用线程池执行清理任务
executor.execute(cleanupRunnable);
// 将新建的连接插入到双端队列中
connections.add(connection);
private final Runnable cleanupRunnable = new Runnable()
@Override public void run()
while (true)
// 内部调用 cleanup() 方法来清理无效的连接
long waitNanos = cleanup(System.nanoTime());
if (waitNanos == -1) return;
if (waitNanos > 0)
long waitMillis = waitNanos / 1000000L;
waitNanos -= (waitMillis * 1000000L);
synchronized (ConnectionPool.this)
try
ConnectionPool.this.wait(waitMillis, (int) waitNanos);
catch (InterruptedException ignored)
;
long cleanup(long now)
int inUseConnectionCount = 0;
int idleConnectionCount = 0;
RealConnection longestIdleConnection = null;
long longestIdleDurationNs = Long.MIN_VALUE;
// Find either a connection to evict, or the time that the next eviction is due.
synchronized (this)
// 遍历所有的连接
for (Iterator<RealConnection> i = connections.iterator(); i.hasNext(); )
RealConnection connection = i.next();
// If the connection is in use, keep searching.
// 遍历所有的连接
if (pruneAndGetAllocationCount(connection, now) > 0)
inUseConnectionCount++;
continue;
idleConnectionCount++;
// If the connection is ready to be evicted, we're done.
// 如果找到了一个可以被清理的连接,会尝试去寻找闲置时间最久的连接来释放
long idleDurationNs = now - connection.idleAtNanos;
if (idleDurationNs > longestIdleDurationNs)
longestIdleDurationNs = idleDurationNs;
longestIdleConnection = connection;
// maxIdleConnections 表示最大允许的闲置的连接的数量,keepAliveDurationNs表示连接允许存活的最长的时间。
// 默认空闲连接最大数目为5个,keepalive 时间最长为5分钟。
if (longestIdleDurationNs >= this.keepAliveDurationNs
|| idleConnectionCount > this.maxIdleConnections)
// We've found a connection to evict. Remove it from the list, then close it below (outside
// of the synchronized block).
// 该连接的时长超出了最大的活跃时长或者闲置的连接数量超出了最大允许的范围,直接移除
connections.remove(longestIdleConnection);
else if (idleConnectionCount > 0)
// A connection will be ready to evict soon.
// 闲置的连接的数量大于0,停顿指定的时间(等会儿会将其清理掉,现在还不是时候)
return keepAliveDurationNs - longestIdleDurationNs;
else if (inUseConnectionCount > 0)
// All connections are in use. It'll be at least the keep alive duration 'til we run again.
// 所有的连接都在使用中,5分钟后再清理
return keepAliveDurationNs;
else
// No connections, idle or in use.
// 没有连接
cleanupRunning = false;
return -1;
从以上的源码分析可知,首先会对缓存中的连接进行遍历,以寻找一个闲置时间最长的连接,然后根据该连接的闲置时长和最大允许的连接数量等参数来决定是否应该清理该连接。同时注意上面的方法的返回值是一个时间,如果闲置时间最长的连接仍然需要一段时间才能被清理的时候,会返回这段时间的时间差,然后会在这段时间之后再次对连接池进行清理。
经过上面对OKHttp内部工作机制的一系列分析,相信你已经对OKHttp已经有了一个比较深入的了解了。首先,我们会在请求的时候初始化一个Call的实例,然后执行它的execute()方法或enqueue()方法,内部最后都会执行到getResponseWithInterceptorChain()方法,这个方法里面通过拦截器组成的责任链,依次经过用户自定义普通拦截器、重试拦截器、桥接拦截器、缓存拦截器、连接拦截器和用户自定义网络拦截器以及访问服务器拦截器等拦截处理过程,来获取到一个响应并交给用户。
其中,除了OKHttp的内部请求流程这点之外,缓存和连接这两部分内容也是两个很重要的点,相信经过讲解,大家对这三部分重点内容已经有了自己的理解。
2.View的绘制流程
Android 中 Activity 是作为应用程序的载体存在,代表着一个完整的用户界面,提供了一个窗口来绘制各种视图,当 Activity 启动时,我们会通过 setContentView 方法来设置一个内容视图,这个内容视图就是用户看到的界面。那么 View 和 activity 是如何关联在一起的呢 ?
①Android的UI层级绘制体系
上图是View与Activity之间的关系,先介绍一下上面这张图
- PhoneWindow:每个Activity都会创建一个Window用来承载View的显示,Window是一个抽象类,PhoneWindow是Window的唯一实现类,该类中包含一个DecorView。
- DecorView:最顶层的View,该View继承自 FrameLayout,它的内部包含两部分,一部分是ActionBar ,另一部分ContentView,
- ContentView:我们 setContentView() 中传入的布局,就在该View中加载显示
- ViewRootImpl:视图层次结构的顶部。一个 Window 对应着一个 ViewRootImpl 和 一个DecorView,通过该实例对DecorView进行控制,最终通过执行ViewRootImpl的performTraversals()开启整个View树的绘制,
②View的加载流程
- 当调用 Activity 的setContentView 方法后会调用PhoneWindow 类的setContentView方法
public void setContentView(@LayoutRes int layoutResID)
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
- PhoneWindow类的setContentView方法中最终会生成一个DecorView对象
@Override
public void setContentView(int layoutResID)
if (mContentParent == null)
//在这里生成一个DecorView
installDecor();
else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS))
mContentParent.removeAllViews();
...
private void installDecor()
mForceDecorInstall = false;
//mDecor 为DecorView
if (mDecor == null)
mDecor = generateDecor(-1);
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0)
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
else
mDecor.setWindow(this);
...
protected DecorView 含泪刷128道面试题,50万字2022最新Android11位大厂面试专题