Cronet 是 Chromium 网络堆栈,可作为库提供给 Android 应用。Cronet 利用多种技术来减少延迟并提高应用正常运行所需的网络请求吞吐量。
Cronet 库每天处理数百万人所用的应用(如 YouTube、Google 应用、Google 相册以及Google 地图导航和 Google 公交)的请求。
Cronet 本身支持 HTTP 协议、HTTP/2 协议和 QUIC 协议。
该库支持您为请求设置优先级标签。服务器可以使用优先级标签来确定处理请求的顺序。
Cronet 可以使用内存缓存或磁盘缓存来存储在网络请求中检索到的资源。后续请求会自动通过缓存提供。
默认情况下,使用 Cronet 库发出的网络请求是异步的。您的工作器线程在等待请求返回时不会遭到屏蔽。
Cronet 支持使用 Brotli 压缩数据格式来压缩数据。
要了解如何在 Android 应用中使用 Cronet 库,请参阅下面的使用。您还可以浏览 GitHub 上的 Cronet 示例。
此次介绍了如何使用 Cronet 库在您的 Android 应用中执行网络操作。Cronet 是 Chromium 网络堆栈,可作为库供在应用中使用。
要在您的项目中为 Cronet 库添加依赖项,请按以下步骤操作:
allprojects {
repositories {
...
google()
}
}
dependencies {
implementation 'com.google.android.gms:play-services-cronet:16.0.0'
}
添加此依赖项后创建的 CronetEngine
对象将使用从 Google Play 服务加载的 Cronet。在创建 CronetEngine 对象之前,请调用 CronetProviderInstaller.installProvider(Context)
对象,以防止在 CronetEngine 创建期间因设备需要更新版 Google Play 服务等错误而抛出异常。
如果无法通过 Google Play 服务加载 Cronet,则只能使用 Cronet API 的一个性能不那么出色的实现。要使用此备用实现,请使用 org.chromium.net:cronet-fallback
并调用 new JavaCronetProvider(context).createBuilder()
。
本部分介绍了如何使用 Cronet 库创建和发送网络请求。发送网络请求后,您的应用应处理网络响应。
该库提供了 CronetEngine.Builder 类,您可以使用此类来创建 CronetEngine 的实例。以下示例展示了如何创建 CronetEngine 对象,分别用java和kotlin创建对象:
JAVA
CronetEngine.Builder myBuilder = new CronetEngine.Builder(context);
CronetEngine cronetEngine = myBuilder.build();
KOTLIN
val myBuilder = CronetEngine.Builder(context)
val cronetEngine: CronetEngine = myBuilder.build()
注意
:建议您仅创建CronetEngine
的一个实例。单个实例可以发送多个异步请求。此外,存储目录不支持多个CronetEngine
实例并发访问。如需了解详情,请参阅setStoragePath()
。
您可以使用 Builder 类来配置 CronetEngine
对象,例如,您可以提供缓存和数据压缩等选项。如需了解详情,请参阅 CronetEngine.Builder
。
要提供回调的实现,请创建 UrlRequest.Callback 的子类,并实现所需的抽象方法,如以下示例所示:
JAVA
class MyUrlRequestCallback extends UrlRequest.Callback {
private static final String TAG = "MyUrlRequestCallback";
@Override
public void onRedirectReceived(UrlRequest request, UrlResponseInfo info, String newLocationUrl) {
Log.i(TAG, "onRedirectReceived method called.");
// You should call the request.followRedirect() method to continue
// processing the request.
request.followRedirect();
}
@Override
public void onResponseStarted(UrlRequest request, UrlResponseInfo info) {
Log.i(TAG, "onResponseStarted method called.");
// You should call the request.read() method before the request can be
// further processed. The following instruction provides a ByteBuffer object
// with a capacity of 102400 bytes to the read() method.
request.read(ByteBuffer.allocateDirect(102400));
}
@Override
public void onReadCompleted(UrlRequest request, UrlResponseInfo info, ByteBuffer byteBuffer) {
Log.i(TAG, "onReadCompleted method called.");
// You should keep reading the request until there's no more data.
request.read(ByteBuffer.allocateDirect(102400));
}
@Override
public void onSucceeded(UrlRequest request, UrlResponseInfo info) {
Log.i(TAG, "onSucceeded method called.");
}
}
KOTLIN
private const val TAG = "MyUrlRequestCallback"
class MyUrlRequestCallback : UrlRequest.Callback() {
override fun onRedirectReceived(request: UrlRequest?, info: UrlResponseInfo?, newLocationUrl: String?) {
Log.i(TAG, "onRedirectReceived method called.")
// You should call the request.followRedirect() method to continue
// processing the request.
request?.followRedirect()
}
override fun onResponseStarted(request: UrlRequest?, info: UrlResponseInfo?) {
Log.i(TAG, "onResponseStarted method called.")
// You should call the request.read() method before the request can be
// further processed. The following instruction provides a ByteBuffer object
// with a capacity of 102400 bytes to the read() method.
request?.read(ByteBuffer.allocateDirect(102400))
}
override fun onReadCompleted(request: UrlRequest?, info: UrlResponseInfo?, byteBuffer: ByteBuffer?) {
Log.i(TAG, "onReadCompleted method called.")
// You should keep reading the request until there's no more data.
request?.read(ByteBuffer.allocateDirect(102400))
}
override fun onSucceeded(request: UrlRequest?, info: UrlResponseInfo?) {
Log.i(TAG, "onSucceeded method called.")
}
}
注意
:为简单起见,上一个代码示例创建了UrlRequest.Callback
的实现,该实现会在发生网络事件时将消息写入日志。要详细了解如何实现回调,请参阅处理网络响应。
您可以使用 Executor 类执行网络任务。要获取 Executor 的实例,请使用返回 Executor 对象的 Executors 类的任一静态方法。以下示例展示了如何使用 newSingleThreadExecutor() 方法创建 Executor 对象:
JAVA
Executor executor = Executors.newSingleThreadExecutor();
KOTLIN
val executor: Executor = Executors.newSingleThreadExecutor()
要创建网络请求,请调用 CronetEngine 的 newUrlRequestBuilder() 方法,并传递目标网址、回调类的实例以及 Executor 对象。newUrlRequestBuilder() 方法将返回 UrlRequest.Builder 对象,您可以使用该对象来创建 UrlRequest 对象,如以下示例所示:
JAVA
UrlRequest.Builder requestBuilder = cronetEngine.newUrlRequestBuilder(
"https://www.example.com", new MyUrlRequestCallback(), executor);
UrlRequest request = requestBuilder.build();
KOTLIN
val requestBuilder = cronetEngine.newUrlRequestBuilder(
"https://www.example.com",
MyUrlRequestCallback(),
executor
)
val request: UrlRequest = requestBuilder.build()
您可以使用 Builder 类来配置 UrlRequest
的实例。例如,您可以指定优先级或 HTTP 谓词。
要启动网络任务,请调用请求的 start()
方法:
JAVA
request.start();
KOTLIN
request.start()
您可以按本部分中的说明使用 Cronet 来创建并发送网络请求。不过,为简单起见,UrlRequest.Callback
的实现示例仅向日志输出消息。以下部分介绍了如何提供支持更多实用场景(例如从响应中提取数据以及检测请求中的故障)的回调实现。
您调用 start()
方法后,系统就会启动 Cronet
请求生命周期。您的应用应在生命周期内通过指定回调来管理请求。要详细了解生命周期,请参阅 Cronet 请求生命周期。您可以通过创建 UrlRequest.Callback
的子类并实现以下方法来指定回调:
JAVA
@Override
public void onRedirectReceived(UrlRequest request, UrlResponseInfo info, String newLocationUrl) {
// Determine whether you want to follow the redirect.
…
if (shouldFollow) {
request.followRedirect();
} else {
request.cancel();
}
}
KOTLIN
override fun onRedirectReceived(request: UrlRequest?, info: UrlResponseInfo?, newLocationUrl: String?) {
// Determine whether you want to follow the redirect.
...
if (shouldFollow) {
request?.followRedirect()
} else {
request?.cancel()
}
}
onResponseStarted()
方法。以下代码展示了该方法的实现示例:JAVA
@Override
public void onResponseStarted(UrlRequest request, UrlResponseInfo info) {
int httpStatusCode = info.getHttpStatusCode();
if (httpStatusCode == 200) {
// The request was fulfilled. Start reading the response.
request.read(myBuffer);
} else if (httpStatusCode == 503) {
// The service is unavailable. You should still check if the request
// contains some data.
request.read(myBuffer);
}
responseHeaders = info.getAllHeaders();
}
KOTLIN
override fun onResponseStarted(request: UrlRequest?, info: UrlResponseInfo?) {
val httpStatusCode = info?.httpStatusCode
if (httpStatusCode == 200) {
// The request was fulfilled. Start reading the response.
request?.read(myBuffer)
} else if (httpStatusCode == 503) {
// The service is unavailable. You should still check if the request
// contains some data.
request?.read(myBuffer)
}
responseHeaders = info?.allHeaders
}
注意
:Cronet 不会将状态代码 4xx 和 5xx 视为错误。您仍应尝试使用read()
方法读取响应,因为其中可能包含某些数据。您也可以使用cancel()
方法取消请求。这些操作可确保请求进入最终状态。
JAVA
@Override
public void onReadCompleted(UrlRequest request, UrlResponseInfo info, ByteBuffer byteBuffer) {
// The response body is available, process byteBuffer.
…
// Continue reading the response body by reusing the same buffer
// until the response has been completed.
byteBuffer.clear();
request.read(myBuffer);
}
KOTLIN
override fun onReadCompleted(request: UrlRequest?, info: UrlResponseInfo?, byteBuffer: ByteBuffer?) {
// The response body is available, process byteBuffer.
...
// Continue reading the response body by reusing the same buffer
// until the response has been completed.
byteBuffer?.clear()
request?.read(myBuffer)
}
JAVA
@Override
public void onSucceeded(UrlRequest request, UrlResponseInfo info) {
// The request has completed successfully.
}
KOTLIN
override fun onSucceeded(request: UrlRequest?, info: UrlResponseInfo?) {
// The request has completed successfully.
}
JAVA
@Override
public void onFailed(UrlRequest request, UrlResponseInfo info, CronetException error) {
// The request has failed. If possible, handle the error.
Log.e(TAG, "The request failed.", error);
}
KOTLIN
override fun onFailed(request: UrlRequest?, info: UrlResponseInfo?, error: CronetException?) {
// The request has failed. If possible, handle the error.
Log.e(TAG, "The request failed.", error)
}
cancel()
方法取消该请求,则调用该方法。调用该方法之后,就不会再调用 UrlRequest.Callback
类的其他方法。您可以使用此方法释放为处理请求而分配的资源。以下示例展示了如何实现该方法:JAVA
@Override
public void onCanceled(UrlRequest request, UrlResponseInfo info) {
// Free resources allocated to process this request.
…
}
KOTLIN
override fun onCanceled(request: UrlRequest?, info: UrlResponseInfo?) {
// Free resources allocated to process this request.
...
}
本部分介绍了使用 Cronet 库创建的请求的生命周期,以及如何使用该库提供的回调方法管理此类请求。
使用 Cronet 库创建的网络请求由 UrlRequest
类表示。以下概念对于理解 UrlRequest
生命周期至关重要:
状态是请求在特定时间所处的特定状况。使用
Cronet
库创建的UrlRequest
对象在其生命周期中会经历不同的状态。请求生命周期包括初始状态以及多个过渡状态和最终状态。
客户端可以根据
UrlRequest
对象的状态对其调用特定的方法。方法会将请求从一种状态转换为另一种状态。
通过实现
UrlRequest.Callback
类的方法,您的应用可以接收有关请求进度的动态更新。您可以实现多种回调方法,从而调用
UrlRequest
对象的方法,将生命周期从一种状态转换为另一种状态。
以下列表介绍了 UrlRequest
生命周期的流程:
start()
方法后,生命周期处于已开始状态。onRedirectReceived()
方法。在此方法中,您可以执行以下任一客户端操作:
- 使用
followRedirect()
跟踪重定向。此方法会将请求恢复为已开始状态。- 使用
cancel()
取消请求。此方法会将请求引导至onCanceled()
方法,借助该方法,应用可以在请求转换为已取消这一最终状态之前执行其他操作。在这里插入代码片
onResponseStarted()
方法。请求处于 Waiting for read()
状态。应用应该会调用 read()
方法来尝试读取部分响应正文。调用 read()
之后,请求处于正在读取状态,并可能出现以下结果:
- 读取操作已成功完成,但还存在更多可用数据。已调用
onReadCompleted()
,且请求再次处于Waiting for read()
状态。应用应再次调用read()
方法,以继续读取响应正文。应用还可以使用cancel()
方法停止读取请求。- 读取操作已成功完成,没有其他可用数据。已调用
onSucceeded()
方法,请求现在处于成功这一最终状态。- 读取操作失败。已调用
onFailed
方法,请求的最终状态为失败。
下图展示了 UrlRequest
对象的生命周期:
Cronet 请求生命周期
参考链接https://developer.android.google.cn/guide/topics/connectivity/cronet