频道栏目
首页 > 资讯 > Android > 正文

bolts全收集流程攻略解析

16-09-08        来源:[db:作者]  
收藏   我要投稿

bolts简介及使用教程:

bolts是Parse被FaceBook收购后开源的一个工具库组合,

Parse声称,与Android AsyncTaskiOS 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 static  Task 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 (Continuation continuation : 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
public  Task 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 static  void 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:

 

public  Task 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 static  void 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

 

public  Task 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 Task continueWhile(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. forResult(null)获取的task称为taskC,taskC调用onSuccessTask()传入我们的continuation,返回一个我们处理并获取结果的taskD,此时taskD调用onSuccessTask(),这样会形成循环,所以使用的时候一定要注意predicate别直接返回true了,一定要有可触发的false返回,否则你程序就得跪了。

接下来是onSuccess():

public  Task 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、多注意一下传入的处理线程是否正确,否则是要搞出个大新闻的。

 

照例没图

做了一点微小的工作,谢谢

相关TAG标签
上一篇:Android图片setBackgroundResource和setImageResource的区别
下一篇:联系人提供程序
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站