Bolts介绍

bolt是Parse和facebook开发的一个供内部使用的底层小工具集合,目前主要包括两方面的内容:
- “Tasks”,可以方便组织管理一系列复杂的异步任务代码,是对Javascript Promise模型的模仿。
- 提供一种App Links protocol的实现,帮助你链接到其他App中的内容和处理传入的deep-links。
本文只介绍Task部分。

官方定义:
A task represents an asynchronous operation. Typically, a Task is returned from an asynchronous function and gives the ability to continue processing the result of the task. When a task is returned from a function, it’s already begun doing its job. A task is not tied to a particular threading model: it represents the work being done, not where it is executing.
简单翻译:
一个任务表示异步操作。通常,一个任务是从一个异步函数返回,并给出了继续处理任务的结果的能力。当任务从一个函数返回时,它就已经开始做它的工作了。一个任务不是和一个特定的线程模型联系在一起:它代表了正在做的工作,而不是在执行的地方。

优点:
- 占用更少的系统资源,因为不会再等待其他任务时阻塞线程。
- 连续执行数个任务不会像只使用回调函数时那样创建嵌套的“金字塔(pyramid)”代码。
- Tasks是完全可组合的,允许开发人员执行分支、并行和复杂的错误处理。
- 开发人员可以按照执行顺序安排基于任务的代码,而不必将逻辑分解到分散的回调函数中。
常用函数:

  • Task.call和Task.callInBackground

该函数会在相关线程执行完任务后返回一个Task来标记任务的执行情况。

  • continueWith和continueWithTask

该函数会在当前task完成后调用Continuation.then方法,可以在该方法查看task是否成功,并获取其返回值。如果需要根据前一个的task返回状态来进行新的异步操作,可以使用continueWithTask方法来代替continueWith,该方法会返回一个新的task,除非新的task完成,否则continueWithTask返回的task也不会变成完成状态,通过这个可以有效的避免多重嵌套。

  • onSuccess和onSuccessTask

多数情况下,只有当前一个task完成你才会做后面的工作,该方法可以帮你先忽略不成功的任务,你可以在后面集中处理它们。

串行任务
一个任务接起前一个任务,只有当前一个任务执行完后,后一个任务才会执行。

Task.call(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                Bitmap bm = cacheMap.get(p);
                if (bm != null) {
                    iv.setImageBitmap(bm);
                    return SUCCESS;
                } else {
                    iv.setImageResource(R.drawable.default_img);
                }
                return FAIL;
            }
        }).onSuccessTask(new Continuation<Integer, Task<Bitmap>>() {
            @Override
            public Task<Bitmap> then(Task<Integer> task) throws Exception {
                int ret = task.getResult();
                if (ret == SUCCESS) {
                    Log.d(TAG, "task finish");
                    return Task.cancelled();
                } else {
                    synchronized (iv) {
                        iv.setTag(p);
                    }
                    return asyncDecodeTask(p);
                }
            }
        }).onSuccessTask(new Continuation<Bitmap, Task<Bitmap>>() {
            @Override
            public Task<Bitmap> then(Task<Bitmap> task) throws Exception {
                final Bitmap bm = task.getResult();
                if (bm != null) {
                    synchronized (iv) {
                        if (((String) iv.getTag()).equals(p)) {
                            iv.setImageBitmap(bm);
                        } else {
                            Log.d(TAG, "has scroll over");
                        }
                    }
                    return Task.cancelled();
                } else {
                    return asyncDownloadTask(p);
                }
            }
        }, Task.UI_THREAD_EXECUTOR).onSuccessTask(new Continuation<Bitmap, Task<Integer>>() {
            @Override
            public Task<Integer> then(Task<Bitmap> task) throws Exception {
                Bitmap bm = task.getResult();
                if (bm != null) {
                    asyncWriteTask(bm, p);
                    synchronized (iv) {
                        if (((String) iv.getTag()).equals(p)) {
                            iv.setImageBitmap(bm);
                        } else {
                            Log.d(TAG, "has scroll over");
                        }
                    }
                    return Task.cancelled();
                } else {
                    return Task.forResult(ERROR);
                }
            }
        }, Task.UI_THREAD_EXECUTOR).continueWith(new Continuation<Integer, Object>() {
            @Override
            public Object then(Task<Integer> task) throws Exception {
                if (task.isFaulted()) {
                    Log.i(TAG, "error log " + task.getError().getMessage());
                }
                if(task.isCancelled()){
                    Log.i(TAG, "has cancelled");
                }
                int ret = task.getResult();
                Log.d(TAG, "ret" + ret);
                return null;
            }
        });

上面是一段异步加载图片的代码,先从缓存中获取,拿不到就尝试从磁盘中获取,再拿不到就从上网络下载,以上只要某一步成功就会取消的后续任务,错误会在最后统一处理。
- 并行任务
如果需要多任务同时进行,要使用whenAll函数,传入一个任务列表。

Task.callInBackground(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                Log.d(TAG, "start download");
                URL url = new URL(FILE_URL);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("GET");
                conn.setConnectTimeout(5000);
                int code = conn.getResponseCode();
                Log.d(TAG, "code " + code);
                if (code == 200) {
                    int length = conn.getContentLength();
                    Log.d(TAG, "length" + length);
                    RandomAccessFile raf = new RandomAccessFile(FILE_NAME, "rwd");
                    //指定创建的这个文件的长度
                    raf.setLength(length);
                    capture.set(length);
                    raf.close();
                    return SUCCESS;
                }
                return FAIL;
            }
        }).onSuccessTask(new Continuation<Integer, Task<Void>>() {
            @Override
            public Task<Void> then(Task<Integer> task) throws Exception {
                List<Task<Void>> lst = new ArrayList<Task<Void>>();
                if (task.getResult() == SUCCESS) {
                    int length = capture.get();
                    int blockSize = length / THREAD_COUNT;
                    for (int i = 0; i < THREAD_COUNT; i++) {
                        if (i == THREAD_COUNT - 1) {
                            lst.add(asyncDownload(i * blockSize, capture.get(), FILE_URL, FILE_NAME));
                        } else
                            lst.add(asyncDownload(i * blockSize, (i + 1) * blockSize, FILE_URL, FILE_NAME));
                    }
                }
                return Task.whenAll(lst);
            }
        }).continueWith(new Continuation<Void, Object>() {
            @Override
            public Object then(Task<Void> task) throws Exception {
                if (task.isFaulted()) {
                    Log.e(TAG, task.getError().getMessage());
                }
                if(task.isCompleted())
                    Log.d(TAG, "finish task!");
                return null;
            }
        });

上面是一段多线程并行分片下载同一个文件的代码,只有当所有的任务全部完成后whenAll的返回值才会变成完成状态,capture是bolts提供的简单泛型封装,允许你在task之间传递数据。
个人理解:
Continuation相当于控制器,应该在Continuation.then中控制调用不同的task,根据返回的task来判断任务执行情况,但实际情况难免有些不同,也可以灵活变通,在then中写业务逻辑。
总结一下,task能方便的帮我们组织和管理异步操作的代码,有效解决回调嵌套问题,使代码结构清晰,但因为java是强类型语言,函数返回值单一,没有javascript灵活,bolts中广泛采用泛型,函数的返回值处理会比较麻烦。本文只是简单介绍,如果想详细了解Bolts和Promise异步编程模型可以参看下面的网站。

以上均是本人的个人理解,如有错误, 欢迎指正!

相关资料:
https://github.com/BoltsFramework/Bolts-Android

http://www.infoq.com/cn/news/2014/02/parse-announces-bolts

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise

https://www.promisejs.org/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值