Android NDK开发详解连接性之使用 Cronet 执行网络操作


Cronet 是 Chromium 网络堆栈,可作为库提供给 Android 应用。Cronet 利用多种技术来减少延迟并提高应用正常运行所需的网络请求吞吐量。

Cronet 库每天处理数百万人所用的应用(如 YouTube、Google 应用、Google 相册以及Google 地图导航和 Google 公交)的请求。
功能

协议支持
Cronet 本身支持 HTTP 协议、HTTP/2 协议和 QUIC 协议。
请求优先级
该库支持您为请求设置优先级标签。服务器可以使用优先级标签来确定处理请求的顺序。
资源缓存
Cronet 可以使用内存缓存或磁盘缓存来存储在网络请求中检索到的资源。后续请求会自动通过缓存提供。
异步请求
默认情况下,使用 Cronet 库发出的网络请求是异步的。您的工作器线程在等待请求返回时不会遭到屏蔽。
数据压缩
Cronet 支持使用 Brotli 压缩数据格式来压缩数据。

要了解如何在 Android 应用中使用 Cronet 库,请参阅发送简单请求。您还可以浏览 GitHub 上的 Cronet 示例。

您可以使用 Chromium 问题跟踪器发送关于 Cronet 库的反馈。请在问题跟踪器中查看错误列表,确保其他人未曾报告您遇到的这个问题。如果错误列表中不存在您要报告的问题,请提交错误,并在摘要行中添加 Cronet 一词。

发送简单请求

本文介绍了如何使用 Cronet 库在您的 Android 应用中执行网络操作。Cronet 是 Chromium 网络堆栈,可作为库供您在应用中使用。如需详细了解该库的功能,请参阅使用 Cronet 执行网络操作。

在您的项目中设置库

要在您的项目中为 Cronet 库添加依赖项,请按以下步骤操作:

在项目的顶层 build.gradle 文件中验证 Android Studio 是否包含对 Google 的 Maven 代码库的引用,如以下示例所示:

allprojects {
        repositories {
            ...
            google()
        }
    }

找到应用模块的 build.gradle 文件,在 dependencies 部分中添加对 Cronet 的 Google Play 服务客户端库的引用,如以下示例所示:

    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 的实例

该库提供了 CronetEngine.Builder 类,您可以使用此类来创建 CronetEngine 的实例。以下示例展示了如何创建 CronetEngine 对象:
Kotlin

    val myBuilder = CronetEngine.Builder(context)
    val cronetEngine: CronetEngine = myBuilder.build()

Java

    CronetEngine.Builder myBuilder = new CronetEngine.Builder(context);
    CronetEngine cronetEngine = myBuilder.build();

注意:建议您仅创建 CronetEngine 的一个实例。单个实例可以发送多个异步请求。此外,存储目录不支持多个 CronetEngine 实例并发访问。如需了解详情,请参阅 setStoragePath()。

您可以使用 Builder 类来配置 CronetEngine 对象,例如,您可以提供缓存和数据压缩等选项。如需了解详情,请参阅 CronetEngine.Builder。

提供请求回调的实现

要提供回调的实现,请创建 UrlRequest.Callback 的子类,并实现所需的抽象方法,如以下示例所示:
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.")
        }
    }

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.");
      }
    }

注意:为简单起见,上一个代码示例创建了 UrlRequest.Callback 的实现,该实现会在发生网络事件时将消息写入日志。要详细了解如何实现回调,请参阅处理网络响应。

创建一个 Executor 对象来管理网络任务

您可以使用 Executor 类执行网络任务。要获取 Executor 的实例,请使用返回 Executor 对象的 Executors 类的任一静态方法。以下示例展示了如何使用 newSingleThreadExecutor() 方法创建 Executor 对象:
Kotlin

 val executor: Executor = Executors.newSingleThreadExecutor()

Java

    Executor executor = Executors.newSingleThreadExecutor();
创建并配置 UrlRequest 对象

要创建网络请求,请调用 CronetEngine 的 newUrlRequestBuilder() 方法,并传递目标网址、回调类的实例以及 Executor 对象。newUrlRequestBuilder() 方法将返回 UrlRequest.Builder 对象,您可以使用该对象来创建 UrlRequest 对象,如以下示例所示:
Kotlin

val requestBuilder = cronetEngine.newUrlRequestBuilder(
            "https://www.example.com",
            MyUrlRequestCallback(),
            executor
    )

    val request: UrlRequest = requestBuilder.build()

Java

    UrlRequest.Builder requestBuilder = cronetEngine.newUrlRequestBuilder(
            "https://www.example.com", new MyUrlRequestCallback(), executor);

    UrlRequest request = requestBuilder.build();

您可以使用 Builder 类来配置 UrlRequest 的实例。例如,您可以指定优先级或 HTTP 谓词。如需了解详情,请参阅 UrlRequest.Builder。

要启动网络任务,请调用请求的 start() 方法:
Kotlin

   request.start()

Java

 request.start();

您可以按本部分中的说明使用 Cronet 来创建并发送网络请求。不过,为简单起见,UrlRequest.Callback 的实现示例仅向日志输出消息。以下部分介绍了如何提供支持更多实用场景(例如从响应中提取数据以及检测请求中的故障)的回调实现。

处理网络响应

您调用 start() 方法后,系统就会启动 Cronet 请求生命周期。您的应用应在生命周期内通过指定回调来管理请求。要详细了解生命周期,请参阅 Cronet 请求生命周期。您可以通过创建 UrlRequest.Callback 的子类并实现以下方法来指定回调:

onRedirectReceived()

在服务器发出 HTTP 重定向代码以响应原始请求时调用。要遵循重定向到达新的目的地,请使用 followRedirect() 方法。否则,请使用 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()
      }
    }

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();
          }
        }

onResponseStarted()

在收到最后一组标头时调用。仅在遵循所有重定向后才调用 onResponseStarted() 方法。以下代码展示了该方法的实现示例:
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
    }

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();
        }
注意:Cronet 不会将状态代码 4xx 和 5xx 视为错误。您仍应尝试使用 read() 方法读取响应,因为其中可能包含某些数据。您也可以使用 cancel() 方法取消请求。这些操作可确保请求进入最终状态。

onReadCompleted()

在读取部分响应正文后调用。以下代码示例展示了如何实现该方法并提取响应正文:
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 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);
        }

onSucceeded()

在网络请求成功完成后调用。以下示例展示了如何实现该方法:
Kotlin
 override fun onSucceeded(request: UrlRequest?, info: UrlResponseInfo?) {
        // The request has completed successfully.
    }
    
Java
        @Override
        public void onSucceeded(UrlRequest request, UrlResponseInfo info) {
          // The request has completed successfully.
        }
        

onFailed()

在调用 start() 方法后,如果由于任何原因而导致请求失败,则调用此方法。以下示例展示了如何实现该方法并获取有关错误的信息:
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)
    }

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);
        }
        

onCanceled()

如果使用 cancel() 方法取消该请求,则调用该方法。调用该方法之后,就不会再调用 UrlRequest.Callback 类的其他方法。您可以使用此方法释放为处理请求而分配的资源。以下示例展示了如何实现该方法:
Kotlin
    override fun onCanceled(request: UrlRequest?, info: UrlResponseInfo?) {
        // Free resources allocated to process this request.
        ...
    }
    
Java
        @Override
        public void onCanceled(UrlRequest request, UrlResponseInfo info) {
          // Free resources allocated to process this request.
          …
        }

本页面上的内容和代码示例受内容许可部分所述许可的限制。Java 和 OpenJDK 是 Oracle 和/或其关联公司的注册商标。

最后更新时间 (UTC):2019-12-27。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五一编程

程序之路有我与你同行

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值