[TOC]
Bolts是一个为了方便移动APP开发而设计的低级库集合。Bolts由Parse和Facebook设计用来我们内部使用的,现在我们决定开源这些库让其他人也可以用。使用这些库不需要添加使用任何Parse的服务,也不需要拥有一个Parse或者Facebook的开发者账号。
Bolts包含:
- “Tasks”,它使得复杂的异步代码更易于管理。一个任务类似于JavaScript的Promise,但是它可以用于ios和Android。
- 一个App Links protocol的实现,帮助您链接到其他应用程序中的内容,并处理传入的多层链接。
想了解更多信息,请参考Bolts Android API Reference。
下载
下载最新的jar包或者在Gradle中定义:
|
|
开发版本的快照可以在Sonatype的snapshots
仓库找到。
Tasks
要创建一个真正的响应式Android程序,你必须让需要耗时操作脱离UI线程,并且要小心翼翼地避免阻塞UI线程。为了更容易得实现这个操作,我们增加了一个叫Task
的类。一个Task
代表一个异步操作。一个Task
通常由一个异步方法返回并且拥有可以继续对这个Task
进行操作的能力。当一个Task
从方法中返回时已经开始执行它的工作了。一个Task
并不与特定的线程模型有关:它代表正在做的工作,而不是在哪里做。相比于callbacks
和AsyncTask
之类的其他异步编程方法,Tasks
拥有很多优势:
- 只消耗少量的系统资源, 因为当等待其他
Task
的时候并不会占用线程。 - 在一条线上执行多个任务,而不是像只使用
callbacks
一样创建金字塔
代码。 Task
是完全可组合的,允许你执行分支,并行和复杂的错误处理,而没有很多命名回调的意大利面条
式代码。- 您可以按照执行的顺序排列基于任务的代码,而不必将其分散到不同的回调函数中。
这个文档的例子假定已经有了一些名为saveAsync
和findAsync
的异步解析方法,它们返回一个Task
。在后面的部分我们会教你如何自定义这些方法。
continueWith
方法
每个Task
都有个叫continueWith
的方法,它接收一个Continuation
对象。Continuation
是一个只有一个then
方法的接口,then
方法在Task
结束时调用。你能在then
方法中检查任务是否成功,也可以拿到任务执行的结果。
|
|
Task
使用了Java的泛型,是强类型的,所以在开始使用的时候要小心一点以免出现语法错误。让我们通过一个例子来更进一步地看下这些类型吧。
|
|
有很多情况是你只需要处理成功回调并且晚点处理失败和取消,可以使用onSuccess
方法替代continueWith
。
|
|
链式任务
Task
有点神奇,因为它让你不用嵌套就能将它们串联在一起。如果你使用continueWithTask
而不是continueWith
,你就能返回一个新的Task
。这个由continueWithTask
返回的Task
直到内层的continueWithTask
返回了新的Task
才会被认为完成了。这可以让你执行多个操作,却不用忍受使用回调产生的金字塔
代码。类似的,onSuccessTask
是onSuccess
的返回Task
版本。因此,使用continueWith
/onSuccess
做更多的同步工作,或者使用continueWithTask
/onSuccessTask
做更多的异步工作。
|
|
错误处理
在选择是否调用continueWith
或者onSuccess
时要小心一点,你可以控制错误如何在你的应用中传递。使用continueWith
来传递错误或者处理错误。你可以把失败的任务看做抛出一个异常。事实上,你可以在continuation里面抛出一个异常,然后会产生一个与此相关的Task
。
|
|
在一串成功回调的最后加一个错误处理器,这样比较方便。
创建任务
当你开始使用时,你只需使用findAsync
或saveAsync
等方法返回的Task
。但是,对于更高级的场景,你可能想要创建你自己的Task
。你可以通过创建一个TaskCompletionSource
来实现。你可以通过该对象创建一个新的Task
,并控制是否将其标记为已完成或已取消。在你创建了一个Task
后,你需要调用setResult
,setError
,或者setCancelled
来触发它的continuation.
|
|
如果你在Task
创建时就知道Task
执行的结果,你可以使用一些更简便的方法。
|
|
创建异步方法
使用这些工具很容易创建自己的带返回Task
的异步方法。比如你能更简单地定义fetchAsync
。
|
|
同样地,创建saveAsync
,findAsync
或deleteAsync
也很容易。我们也提供了一些便捷的方法帮助你从直接代码块创建Task
。callInBackground
在我们的后台线程池运行一个Task
,而call
则是尝试立即执行它的代码块。
|
|
顺序任务
当你想要按顺序执行一系列的异步操作时,Task是非常方便的,每个操作都会等待上一个操作完成。比如说,想象你要删除所有你博客中的评论。
|
|
并行任务
你也可以使用whenAll
方法来并行执行几个Task
。你可以一次性开始多个操作并且使用Task.whenAll
来创建一个新的Task
,当所有输入的Task
都完成时,这个Task
将被标记为完成。
只有当所有传入的Task
都成功之后这个新Task
才算成功。虽然并行执行操作比顺序执行更快,但是可能会消耗更多的系统资源和带宽。
|
|
Task Executors
所有的continueWith
和onSuccess
方法都可以使用一个java.util.concurrent.Executor
作为可选的第二个参数。Executor
允许你控制continuation的执行方式。Task.call()
会调用当前线程的Callable
而Task.callInBackground
会使用它自己的线程池,但是你也能指定你自己的executor来调度不同的线程。比如你想在特定的线程池执行工作:
|
|
|
|
一般情况下,像在主线程分发这种,我们提供了默认的Executor,包含Task.UI_THREAD_EXECUTOR
和Task.BACKGROUND_EXECUTOR
。举个例子:
|
|
捕获变量
在多个回调中分解代码的一个困难在于它们具有不同的变量作用域。 Java允许函数从外部范围“捕获”变量,但只有当它们被标记为final
时,才使它们变得不可变,这是不方便的。 这就是为什么我们添加了另一个便捷的类Capture
,它可以让你与回调共享一个变量。只需要调用变量的get
和set
方法来改变它的值。
|
|
取消Task
要想取消一个Task
,首先创建一个CancellationTokenSource
,然后把CancellationTokenSource
的响应token传递到你要取消的Task
中,然后调用CancellationTokenSource
的cancel()
方法即可。这将取消任何正在执行的token绑定的Task
。
|
|
要想使用token来取消一个异步的调用,首先你得修改任务的方法,让它可以接收一个CancellationToken
并且使用isCancellationRequested()
方法来决定何时停止操作。
|
|
App Links
App Links 提供了一个跨平台的机制让开发者可以为他们的内容定义和发布一个多层链接的scheme,允许其他APP直接连接。不管你是构建一个接收传入链接的还是可能链接到其他app内容的app,Bolts都会提供工具来简化App链接协议的实现。
处理App Link
最常见的情况是让你的app可以接收App Link。
App Link让你的用户可以在他们的设备上快速访问最丰富的、最原生的内容呈现。Bolts通过提供一系列处理传入Intent
的工具来简化处理传入的App Link。
比方说,你可以在你的Activity
中使用AppLinks
工具类来解析传递过来的Intent
:
|
|
导航到一个url
通过App Link,你的应用程序可以在用户导航到链接时提供最佳用户体验(由接收应用定义)。 Bolts简化了这个过程,自动执行跟踪链接所需的步骤:
在指定的URL从HTML获取应用链接元数据解析的应用链接
逐步执行与正在使用的设备相关的App Link targets,检查设备上是否存在可以处理targets的应用
如果应用程序存在,请使用指定的al_applink_data构建“Intent”,并导航到“Intent”
否则,请使用指定的原始网址打开浏览器
在最简单的情况下,只需一行代码即可导航到可能具有App Link的URL:
|
|
添加应用和导航数据
在大多数情况下,导航时需要传递给应用程序的数据将包含在URL本身中,因此无论应用程序是否安装在设备上,用户都将看到正确的内容。 然而有时候应用程序会传送与应用间导航相关的资料,或是想利用应用程序使用的信息来修改App链接协议,以调整应用程序的行为(比如一个显示回引用应用程序的链接)。
如果你想要充分利用这些特性,你可以拆分导航过程。 首先,你必须拥有您要导航的应用程序链接:
|
|
然后,你可以使用你想导航的附加数据构建一个APP Link请求:
|
|
解决应用程序链接元数据
Bolts允许自定义App Link方案,可以用作性能优化(例如缓存元数据)或作为允许开发人员使用集中式索引来获得App Link元数据的机制。 一个自定义的App Link解析器只需要能够获取URL并返回一个包含适用于此设备的AppLink.Target的有序列表的AppLink。 Bolts创造性地提供了其中之一,使用隐藏的“WebView”在设备上执行此方案。
你可以重写AppLinkNavigation
中的一个方法来使用任意的实现了AppLinkResolver
接口的解析器:
|
|
或者,你可以使用内置API替换掉默认的解析器:
|
|
分析
Bolts介绍测量事件。 应用程序链接将两个Measurement Events广播到应用程序,该应用程序可以捕获并与应用程序中的现有分析组件集成。(启用Analytics需要Android Support Library v4)
al_nav_out
— 当您的应用发送App链接URL时引发。al_nav_in
— 当您的应用打开传入的应用链接Url或Intent
时触发。
监听App链接测量事件
还有其他分析工具与Bolts的应用程序链接事件相集成,但你也可以自己收听这些事件:
|
|
应用链接事件字段
应用程序链接测量事件以字符串键值对形式从应用程序链接Intent中发送附加信息。 下面是一些对两个事件的有用字段:
al_nav_in
inputURL
: 打开app的URL。inputURLScheme
:inputURL
的scheme。refererURL
: 引用app添加进al_applink_data
:referer_app_link
的URLrefererAppName
: 引用app添加进al_applink_data
:referer_app_link
的名字.sourceApplication
: 来源app的bundletargetURL
:al_applink_data
中的target_url
字段.version
: App Links API 版本.
al_nav_out
outputURL
: 用于打开其他应用程序(或浏览器)的URL。 如果有对应的的应用程序要打开,这将是“al_applink_data”中的自定义scheme的url / intent。outputURLScheme
:outputURL
的scheme。sourceURL
: 应用程序链接meta标签中的页面URLsourceURLHost
: sourceURL的host名字。success
: “1”表示在其他应用程序或浏览器中打开应用程序链接成功;“0”
表示无法打开App Link。type
:“app”
表示在应用程序中打开,“web”
表示在浏览器中打开;“fail”
表示成功字段为“0”`。version
: App Links API版本。