使用 Kotlin 进行 Android 编程
by Pierre-Olivier Laurence, Amanda Hinchman-Dominguez, G. Blake Meike, Mike Dunn
第 6 章 使用回调处理并发性 使用回调处理并发性
本作品已使用人工智能进行翻译。欢迎您提供反馈和意见:translation-feedback@oreilly.com
Kotlin 中处理并发性的惯用方法是使用例程。不过,在 Java 中使用线程和回调处理并发问题已经有一段时间了。那么我们为什么需要使用例程呢?
为了回答这个问题,我们将重温 Android 上典型的 Kotlin 实现,并讨论使用线程的误区。了解传统方法的薄弱点是理解设计例程背后动机的关键。
在 Android 应用程序中,长期运行的任务不应该在 UI 线程上完成,这在上一章中已经提到过。 如果阻塞了主线程(即 UI 线程),你的应用程序可能无法获得绘制屏幕或适当更新屏幕所需的资源。 事实上,如果你试图在 UI 线程上进行明显的 IO 调用(如建立 HTTP 连接),lint 就会抱怨。
当主线程在小于框架时间(在大多数设备上为 16 毫秒)内完成所有任务时,Android 应用程序就能流畅运行。这是一个相当短的时间,所有阻塞调用,如网络请求(阻塞 IO),都应在后台线程上执行。1
将任务委托给另一个线程时,通常会调用一个函数来启动异步任务。在某些情况下,这是 "触发后忘记",但您通常在等待结果,而且需要对结果采取行动。为此,需要提供一个函数,一旦作业完成,该函数就会被调用。该函数被称为回调函数。 回调函数通常接受参数,因此后台线程通常会用作业结果调用回调函数。 在计算完成后调用任意函数或注入函数的做法被称为回调模式。
使用回调是相当高效的,不过它也有一些局限和缺点。为了说明这一点,我们将在 Kotlin 中实现一个简单而现实的示例。例程可以解决回调的所有问题,但在直接进入例程之前,了解例程旨在解决哪些问题非常重要。
购买示例功能
假设您正在开发一个 Android 应用程序的付费功能。用户注册后,您要检查该用户已进行的购买列表,然后对其采取行动。要获取购买列表,让我们使用一个名为BillingClient 的对象。请注意,我们使用的不是 Android 框架提供的BillingClient ,而是com.android.billingclient.api.BillingClient 。我们使用的是自己的基本概念的简单版本,如下代码所示:
interfaceBillingClient{funinterfaceBillingCallback{funonInitDone(provider:PurchasesProvider?)}/* Implementations should be nonblocking */funinit(callback:BillingCallback)}
典型的任务流程是
-
初始化与
BillingClient的连接。等待它准备就绪--回调提供一个PurchasesProvider,或在出错时提供 null。目前,我们不会处理错误。 -
使用返回的
PurchasesProvider异步获取用户的购买列表。您的程序将等待响应,响应中将包含购买列表和一些附加元数据。 -
对这些新信息做出 React;您可能会通过用户界面显示购买清单,以提供更多详细信息,或请求状态、取消订单中的某个项目等。
为便于进一步参考,我们将前面的流程称为我们的逻辑。
如您所见,这只是一个接口,只有一个方法,输入为BillingCallback 。BillingCallback 是在BillingClient 接口内部声明的,因为这个回调只在 ...