bolts简介及使用教程:
bolts是Parse被FaceBook收购后开源的一个工具库组合,
Parse声称,与Android AsyncTask和iOS NSOperation相比,Tasks有若干优势,其中包括:
l连续执行数个任务不会像只使用回调函数时那样创建嵌套的“金字塔(pyramid)”代码。
lTasks是完全可组合的,允许开发人员执行分支、并行和复杂的错误处理。
l开发人员可以按照执行顺序安排基于任务的代码,而不必将逻辑分解到分散的回调函数中。
github地址 https://github.com/BoltsFramework/Bolts-Android
疑似官方解释:http://gold.xitu.io/entry/55cdcca040ac79db35731770
我们先来看一下如何使用
gradle下加入
dependencies { compile 'com.parse.bolts:bolts-android:1.2.0' }
代码里面使用:
Task.call(new Callable() { @Override public Boolean call() throws Exception { // 处理一些具体的动作 return false; } }, Task.BACKGROUND_EXECUTOR);
第一个参数是一个Callable,conCurrent包的,常与线程池、Future搭配使用。
这里有两个线程可以供我们使用Task.UI_THREAD_EXECUTOR、Task.BACKGROUND_EXECUTOR,不传这个参数的话默认为Task.IMMEDIATE_EXECUTOR,也就是在当前线程下执行。
如果只是这么简单的话我们用个线程池也可以,没必要搞这么多,下面我们来看看进阶用法,这个call方法会返回生成的Task对象,我们可以继续对这个对象进行处理
Task.continueWith(new Continuation() { @Override public String then(Task task) throws Exception { return null; } })
这个api可谓是简单易懂,无论这个Task成功或者失败,这个Continuation都能接受到结果并进行你的处理,最重要的是,会返回一个新的Task,你可以在后面再接一个continueWith();然后实现无限续杯,这比RxJava的使用map来转换不知道高到哪里去了。
当然,还要学习一个:
task.onSuccess(new Continuation() { @Override public Object then(Task task) throws Exception { return null; } });
这个onSuccess方法只有Task被成功执行并且没有报错的情况下才会被调用,也就是说,Task内部帮我们处理了(其实只是简单的把报错信息封装起来)运行时可能出现的各种错误,这样我们就只会在一切正常的情况下调用我们的代码,以防出现各种奇怪的错误。
还要再学习一个:
task.continueWhile(new Callable() { @Override public Boolean call() throws Exception { return null; } }, new Continuation >() { @Override public Task then(Task task) throws Exception { return null; } });
continueWhile这个方法需要两个参数,一个是Callable,要求返回Boolean值,表示你的任务是否被成功执行,如果成功执行,会调用接下来的另一个参数Continuation。
接下来我们要搞个大新闻:
task.continueWithTask(new Continuation>() { @Override public Task then(Task task) throws Exception { return null; } });
continueWithTask这个方法用起来就麻烦啦,使用的时候泛型参数一定要返回一个Task对象,否则内部会报错,至于为什么我们等下源码分析再说。
那这个方法干什么用的呢?你调用continueWithTask 返回的Task_A会在Continuation里面你自己返回的Task_B完成之后完成,这个方法解决了金字塔嵌套问题。
以上这四个方法都可以选择线程Task.UI_THREAD_EXECUTOR、Task.BACKGROUND_EXECUTOR,不传这个参数的话默认为Task.IMMEDIATE_EXECUTOR。
那么接下来我们来讲一下bolts的源代码
在开始之前要提一下CancellationToken,这个参数,目前来说这个参数并没有用上,我们也不可以在包外访问这个类,在bolts内部是传null进行参数填充的,并且在源码中也不会被用到,可能会在后面的版本更新中派上用场,以下内容不会对该类再进行解释,也不会提及指定了该参数的传参方法。
从Task.Call开始讲吧
public staticTask call(final Callable callable) { return call(callable, IMMEDIATE_EXECUTOR, null); } public static Task call(final Callable callable, Executor executor){ return call(callable, executor, null); } public static Task callInBackground(Callable callable) { return call(callable, BACKGROUND_EXECUTOR, null); } //上面这三个方法都会调用到下面这个,我们只需要看这个就好了 public static Task call(final Callable callable, Executor executor, final CancellationToken ct) { //这个TaskCompletionSource是一个包装类,构造方法内实例化了一个Task,里面所有//的setXXXX方法都会调用到所持有的Task本身的trySetXXXX方法,这种trySet方法//会返回一个boolean值表示是否执行成功,如果没有成功,TaskCompletionSource会抛//出一个IllegalStateException异常。 final bolts.TaskCompletionSource tcs = new bolts.TaskCompletionSource<>(); try { executor.execute(new Runnable() { @Override public void run() { //这里ct 必定为null,不用管 if (ct != null && ct.isCancellationRequested()) { tcs.setCancelled(); return; } try { tcs.setResult(callable.call()); } catch (CancellationException e) { tcs.setCancelled(); } catch (Exception e) { tcs.setError(e); } } }); } catch (Exception e) { tcs.setError(new ExecutorException(e)); } //返回内部task实例 return tcs.getTask(); }
通过指定的Exeutor在特定线程执行一个Runnable,并调用我们所传进来的callable的call方法,并返回已经设置了结果的task。
那么我们来看看设置结果的方法,这三个方法都不能从包外部访问:
/** * Sets the cancelled flag on the Task if the Task hasn't already been completed. */ /* package */ boolean trySetCancelled() { synchronized (lock) { if (complete) { return false; } complete = true; cancelled = true; lock.notifyAll(); runContinuations(); return true; } } /** * Sets the result on the Task if the Task hasn't already been completed. */ /* package */ boolean trySetResult(TResult result) { synchronized (lock) { if (complete) { return false; } complete = true; Task.this.result = result; lock.notifyAll(); runContinuations(); return true; } } /** * Sets the error on the Task if the Task hasn't already been completed. */ /* package */ boolean trySetError(Exception error) { synchronized (lock) { if (complete) { return false; } complete = true; Task.this.error = error; errorHasBeenObserved = false; lock.notifyAll(); runContinuations(); //这个UnobservedExceptionHandler是我们自己设置的异常处理器,没设就不用管下面这一句了 if (!errorHasBeenObserved && getUnobservedExceptionHandler() != null) unobservedErrorNotifier = new UnobservedErrorNotifier(this); return true; } }
上面这三个方法就是刚刚说过的trySetXXXX系列方法,基本上都是大同小异,首先判断任务是否已经结束,false就让TaskCompletionSource抛异常,true则设置complete 状态,并且解开lock对象锁,设置结果还是设置异常信息就不解释了。
我们来看一下这个共同调用的runContinuations()方法
private void runContinuations() { //对象锁 synchronized (lock) { for (Continuationcontinuation : continuations) { try { //这里传入task continuation.then(this); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } continuations = null; } }
上面所遍历的continuations是一个ArrayList对象,当我们调用continueWith等方法时会往里面塞Continuation,这个也没什么好说的。
我们继续说下一个
Task.continueWith publicTask continueWith( Continuation continuation) { return continueWith(continuation, IMMEDIATE_EXECUTOR, null); } public Task continueWith( final Continuation continuation, final Executor executor) { return continueWith(continuation, executor, null); } //上面两个会调用下面这个 public Task continueWith( final Continuation continuation, final Executor executor, final CancellationToken ct) { boolean completed; final bolts.TaskCompletionSource tcs = new bolts.TaskCompletionSource<>(); //同步锁 synchronized (lock) { completed = this.isCompleted(); if (!completed) { //往列表里面加东西,当任务完成时遍历此列表并调用then()方法 this.continuations.add(new Continuation () { @Override public Void then(Task task) { completeImmediately(tcs, continuation, task, executor, ct); return null; } }); } } if (completed) { completeImmediately(tcs, continuation, this, executor, ct); } return tcs.getTask(); }
上面判断了一下任务是否已经完成,视情况调用completeImmediately()方法
private staticvoid completeImmediately( final bolts.TaskCompletionSource tcs, final Continuation continuation, final Task task, Executor executor, final CancellationToken ct) { try { executor.execute(new Runnable() { @Override public void run() { //这里ct 必定为null,不用管 if (ct != null && ct.isCancellationRequested()) { tcs.setCancelled(); return; } try { //这里跟上面Call()方法中调用callable.call()差不多 TContinuationResult result = continuation.then(task); tcs.setResult(result); } catch (CancellationException e) { tcs.setCancelled(); } catch (Exception e) { tcs.setError(e); } } }); } catch (Exception e) { tcs.setError(new ExecutorException(e)); } }
这个方法里面给传进来的tcs设置了一个结果,然后在continueWith()方法的最后取出该tcs的task实例返回给调用者。
接下来这个就有点麻烦了
continueWithTask:
publicTask continueWithTask( Continuation > continuation) { return continueWithTask(continuation, IMMEDIATE_EXECUTOR, null); } public Task continueWithTask( final Continuation > continuation, final Executor executor) { return continueWithTask(continuation, executor, null); } public Task continueWithTask( final Continuation > continuation, final Executor executor, final CancellationToken ct) { boolean completed; final bolts.TaskCompletionSource tcs = new bolts.TaskCompletionSource<>(); synchronized (lock) { completed = this.isCompleted(); if (!completed) { this.continuations.add(new Continuation () { @Override public Void then(Task task) { completeAfterTask(tcs, continuation, task, executor, ct); return null; } }); } } if (completed) { completeAfterTask(tcs, continuation, this, executor, ct); } return tcs.getTask(); }
这个跟上面提到的continueWith结构相同,只是最后调用的complete方法有所差别
我们先来解释一下这个思路:
我们调用Task.call()获得一个taskA,然后调用taskA.continueWithTask()获得返回的taskB,然后再continueWithTask方法中我们会传进去一个返回结果为Task的taskC对象,taskB会在taskC完成之后再setResult
private staticvoid completeAfterTask( final bolts.TaskCompletionSource tcs, final Continuation > continuation, final Task task, final Executor executor, final CancellationToken ct) { try { executor.execute(new Runnable() { @Override public void run() { //这里ct 必定为null,不用管 if (ct != null && ct.isCancellationRequested()) { tcs.setCancelled(); return; } try { //这里这个result就是我们说的taskC,tcs里面的Task实例就是taskB,并且会返回taskB给调用者 Task result = continuation.then(task); if (result == null) { tcs.setResult(null); } else { result.continueWith(new Continuation () { @Override public Void then(Task task) { if (ct != null && ct.isCancellationRequested()) { tcs.setCancelled(); return null; } if (task.isCancelled()) { tcs.setCancelled(); } else if (task.isFaulted()) { tcs.setError(task.getError()); } else { tcs.setResult(task.getResult()); } return null; } }); } } catch (CancellationException e) { tcs.setCancelled(); } catch (Exception e) { tcs.setError(e); } } }); } catch (Exception e) { tcs.setError(new ExecutorException(e)); } }
除了上面注释所说的还有一点要注意的是,taskB会将taskC的结果作为自己的结果,也就是多嵌套了一层而已。
onSuccessTask
publicTask onSuccessTask( final Continuation > continuation) { return onSuccessTask(continuation, IMMEDIATE_EXECUTOR); } public Task onSuccessTask( final Continuation > continuation, Executor executor) { return onSuccessTask(continuation, executor, null); } public Task onSuccessTask( final Continuation > continuation, Executor executor, final CancellationToken ct) { return continueWithTask(new Continuation >() { @Override public Task then(Task task) { if (ct != null && ct.isCancellationRequested()) { return Task.cancelled(); } if (task.isFaulted()) { return Task.forError(task.getError()); } else if (task.isCancelled()) { return Task.cancelled(); } else { return task.continueWithTask(continuation); } } }, executor); }
我们可以从源代码看出,taskA调用了continueWithTask传入一个匿名continuation得到taskB,在taskA正常的、无报错,即成功的状态下,taskA会调用continueWithTask(),此时传入一开始我们传进来的continuation,然后再执行我们所期望的操作。此时return一个taskC,taskC的结果为我们的continuation返回的taskD的结果。
接下来是continueWhile:
public TaskcontinueWhile(Callable predicate, Continuation > continuation) { return continueWhile(predicate, continuation, IMMEDIATE_EXECUTOR, null); } public Task continueWhile(final Callable predicate, final Continuation > continuation, final Executor executor) { return continueWhile(predicate, continuation, executor, null); } //上面两个调用下面这个 public Task continueWhile(final Callable predicate, final Continuation > continuation, final Executor executor, final CancellationToken ct) { final Capture<> >> predicateContinuation = new Capture<>(); predicateContinuation.set(new Continuation >() { @Override public Task then(Task task) throws Exception { //这里ct 必定为null,不用管 if (ct != null && ct.isCancellationRequested()) { return Task.cancelled(); } if (predicate.call()) { return Task. forResult(null).onSuccessTask(continuation, executor) .onSuccessTask(predicateContinuation.get(), executor); } //返回一个一个已经结束且result为null的task return Task.forResult(null); } }); //此时makeVoid()会调用Task.forResult(null) return makeVoid().continueWithTask(predicateContinuation.get(), executor); }
这段代码中我们可以直接阅读最后的return语句,这个时候就调用到了我们之前讲的continueWithTask,
而Capture是一个简单的类,可以临时存储一个泛型变量,这次的predicateContinuation则存储了一个返回值类型为Tsak的Continuation对象。
调用continueWhile之后我们获取了一个taskA,这个taskA会在Continuation返回的taskB结束后结束,并将taskB的结果作为自己的结果,而taskB是第n行中ruturn的。我们把这一行中使用Task.
接下来是onSuccess():
publicTask onSuccess( final Continuation continuation) { return onSuccess(continuation, IMMEDIATE_EXECUTOR, null); } public Task onSuccess( final Continuation continuation, Executor executor) { return onSuccess(continuation, executor, null); } //上面两个调用下面这个 public Task onSuccess( final Continuation continuation, Executor executor, final CancellationToken ct) { return continueWithTask(new Continuation >() { @Override public Task then(Task task) { if (ct != null && ct.isCancellationRequested()) { return Task.cancelled(); } if (task.isFaulted()) { return Task.forError(task.getError()); } else if (task.isCancelled()) { return Task.cancelled(); } else { return task.continueWith(continuation); } } }, executor); }
这个跟onSuccessTask差不多,成功的时候执行一个continuation而已,没什么特别需要解释的。
到这里,Task的api和相应的源码解释就差不多完成了,下面说一些零散的使用技巧
1、当你需要一个task来调用某些方法时可以使用Tsak.forResult(null)来获取一个实例,或者直接使用new Task(null)来获取一个实例。
2、多使用xxxxxTask方法来避免金字塔代码堆叠
3、有需要可以自己传一个异常处理器进去处理你可能出现的异常
4、多注意一下传入的处理线程是否正确,否则是要搞出个大新闻的。
照例没图
做了一点微小的工作,谢谢