Parse开源了一个面向iOS和Android的底层库集合,统称为Bolts。根据Parse的公告,Bolts是Parse和Facebook共同努力将两家公司各自独立开发的小型底层工具类合并的结果。Bolts-Android为一个级联的异步任务。
Bolts-Android github地址:
https://github.com/BoltsFramework/Bolts-Android
本文案例的 github地址:
https://github.com/AndroidHighQualityCodeStudy/Android_Task_ThirdCode_Bolts
一、Bolts 使用
任务抛到某个线程执行
:当前线程、后台线程、UI线程执行任务任务级联执行
:UI线程、后台线程、UI线程执行任务任务并行执行
:Task.whenAll 多任务并行执行自定义任务线程池
延时执行任务
取消执行的任务
1.1 任务抛到某个线程执行
任务切换到当前线程
、后台线程
或 UI线程
执行。
- 后台线程:网络请求、DB请求;
- UI线程:主线程或UI更新相关操作
// 第1部分:当前线程、后台线程、UI线程运行任务
//
// 运行在当前线程中
public Task<Boolean> runOnCurrentThread() {
//
return Task.call(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
// Current_Thread
return true;
}
});
}
// 运行在后台线程
public Task<Boolean> runOnBackgroundThread() {
//
return Task.call(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
// Background_Thread
return true;
}
}, Task.BACKGROUND_EXECUTOR);
}
// 运行在UI线程中
public Task<Boolean> runOnUIThread() {
//
return Task.call(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
// UI_Thread
return true;
}
}, Task.UI_THREAD_EXECUTOR);
}
1.2 任务级联执行
任务先在UI线程
执行,然后返回结果切换到后台线程
执行,最后再次切换到UI线程
执行。
// 第2部分:UI线程、后台线程、UI线程运行任务
//
// 任务顺序执行
public Task synchronousTask(CancellationToken cancellationToken) {
return Task.call(new Callable<Void>() {
@Override
public Void call() throws Exception {
// UI_Thread
LogUtils.d(TAG, "---1 UI_Thread---");
return null;
}
}, Task.UI_THREAD_EXECUTOR, cancellationToken).onSuccess(new Continuation<Void, Boolean>() {
@Override
public Boolean then(Task<Void> task) throws Exception {
// Background_Thread
LogUtils.d(TAG, "---2 Background_Thread---");
return true;
}
}, Task.BACKGROUND_EXECUTOR).continueWith(new Continuation<Boolean, Void>() {
@Override
public Void then(Task<Boolean> task) throws Exception {
// UI_Thread
LogUtils.d(TAG, "---3 UI_Thread---");
return null;
}
}, Task.UI_THREAD_EXECUTOR);
}
1.3 任务并行执行
Task.whenAll
多任务并行执行
举例:
//多任务并行
public void whenAll() {
ArrayList<Task<Void>> tasks = new ArrayList<Task<Void>>();
for (int i = 0; i < 3; i++) {
final int index = i;
// Start this delete immediately and add its task to the list.
tasks.add(Task.call(new Callable<Void>() {
@Override
public Void call() throws Exception {
// UI_Thread
LogUtils.d(TAG, "---###########################---");
LogUtils.d(TAG, "index: " + index);
return null;
}
}, Task.BACKGROUND_EXECUTOR));
}
Task.whenAll(tasks);
}
1.4 自定义任务线程池
我们除了有 Task.BACKGROUND_EXECUTOR 线程池
,还可以自定义执行任务的线程池,例如下文自定的 NETWORK_EXECUTOR(只处理网络请求)
、DISK_EXECUTOR(只处理Sdcard的读写)
等线程池。
// 自定义线程池
static final Executor NETWORK_EXECUTOR = Executors.newCachedThreadPool();
static final Executor DISK_EXECUTOR = Executors.newCachedThreadPool();
//
public void changeThreadPool() {
Task.call(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
// NETWORK_Thread
return null;
}
}, NETWORK_EXECUTOR).continueWith(new Continuation<Boolean, String>() {
@Override
public String then(Task<Boolean> task) throws Exception {
// NETWORK_Thread
return null;
}
}).continueWith(new Continuation<String, Integer>() {
@Override
public Integer then(Task<String> task) throws Exception {
// DISK_Thread
return null;
}
}, DISK_EXECUTOR);
}
1.5 延时执行任务
Task.delay(100).continueWith(new Continuation<Void, Void>() {
@Override
public Void then(Task<Void> task) throws Exception {
mTcpSocketAgent.initClientSocket(serverIp);
mTcpSocketAgent.addMsgCallback(mTcpMsgCallback);
mTcpSocketAgent.startConnect();
return null;
}
},Task.UI_THREAD_EXECUTOR);
1.6 取消执行的任务
取消执行的任务。
//取消任务
public void cancelTask() {
CancellationTokenSource cts = new CancellationTokenSource();
Task<Boolean> stringTask = runOnBackgroundThread(cts.getToken());
cts.cancel();
}
//运行在后台线程中
public Task<Boolean> runOnBackgroundThread(CancellationToken cancellationToken) {
//
return Task.call(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
// Background_Thread
return true;
}
}, Task.BACKGROUND_EXECUTOR, cancellationToken);
}
二、Bolts 原理
通过跟踪源码的形式,了解其运行原理。
- 1、每一个
Task类的对象
,均包含一个Continuation列表
,用来管理当前Task对象全部的Continuation任务
// 每一个Task对象都有一个自己的Continuation队列(continuations非全局,这样不同task的continuation就不会混淆)
private List<Continuation<TResult, Void>> continuations = new ArrayList<>();
- 2、
Continuation任务的执行时机
当前Task对象的call()方法运行结束后,会调用trySetResult()
方法,将运行结果保存下来;并循环执行continuations列表中的任务
。
Task.java类中trySetResult方法:
//当前task,执行结束后的返回数据赋值
//Sets the result on the Task if the Task hasn't already been completed.
boolean trySetResult(TResult result) {
synchronized (lock) {
// 任务运行结束判断
if (complete) {
return false;
}
// 任务运行结束
complete = true;
// 任务结果赋值
Task.this.result = result;
// 唤醒lock wait等待(如果之前调用过waitForCompletion阻塞线程,那么此处会被唤醒)
lock.notifyAll();
// 循环执行continuations任务
runContinuations();
return true;
}
}
- 3、Task.java类中
runContinuations
方法:
每一个Continuation又是一个封装的Continuation.then()
方法中将任务提交到的不同线程池
.
// 循环执行continuations任务
// 问题: Continuation并没有区分执行线程呀?
// 答:每一个Continuation又是一个封装的Continuation.then(),方法中将任务提交到的不同线程池
private void runContinuations() {
synchronized (lock) {
// 循环运行当前continuations列表任务
for (Continuation<TResult, ?> continuation : continuations) {
try {
// 执行Continuation任务
continuation.then(this);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// 当前Task的continuations队列置空
continuations = null;
}
}
- 4、continuations
如何将不同任务提交到不用的线程池
每一个Continuation又是一个封装的Continuation.then(),方法中将任务提交到的不同线程池
下文代码可以看出每次提交的Continuation任务中,均封装了一个completeImmediately(tcs, continuation, task, executor, ct);
来确定其运行的线程池等信息。
Task.java类中continueWith方法:
public <TContinuationResult> Task<TContinuationResult> continueWith(
final Continuation<TResult, TContinuationResult> continuation, final Executor executor,
final CancellationToken ct) {
// 上次task的完成情况
boolean completed;
// 构建一个新的task
final TaskCompletionSource<TContinuationResult> tcs = new TaskCompletionSource<>();
//
synchronized (lock) {
// 上次task的完成情况
completed = this.isCompleted();
// 如果上次task 未完成,添加到task列表
if (!completed) {
// 向continuations队列中添加一个“需提交到不同线程池执行的task任务”
this.continuations.add(new Continuation<TResult, Void>() {
@Override
public Void then(Task<TResult> task) {
//
completeImmediately(tcs, continuation, task, executor, ct);
return null;
}
});
}
}
// 上次任务完成,当前线程执行
if (completed) {
completeImmediately(tcs, continuation, this, executor, ct);
}
//
return tcs.getTask();
}
- 5、可通过Task类waitForCompletion()方法,阻塞当前线程,直到Task任务运行结束
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ji-chu/103006.html