Bolts框架在安卓中的简单应用

在新公司的项目中,是由bolts框架来搭建网络请求的,由于之前没有接触过这个框架,因此只能从头看起(其实看下来相对来说我更喜欢用RxJava+Retrofit搭建apps的请求层,but,whatever...),下面的内容很多都是在网上看完资料后自己写Demo来验证获得的,部分是翻译GitHub的Bolts框架的说明文档,也有部分是我自己在网上的教程的基础上自己验证后的代码,如有雷同,纯属巧合。

1、简介

Bolts是一个用于简化移动app开发的轻量级函数库集合,是由Parse和Facebook编写来进行内部使用的,后来他们决定开源,提供给广大开发者使用。“Tasks”,使复杂的异步代码结构变得易于管理。“Task”的作用在Android和ios中就像是JavaScript的Promise。

2、下载

这里下载jar包或者在Gradle中进行编译。

dependencies {
  compile 'com.parse.bolts:bolts-tasks:1.4.0'
  compile 'com.parse.bolts:bolts-applinks:1.4.0'
}

3、Tasks

为了构建一个响应迅速的Android应用,你不能在UI线程中运行任何的耗时操作,并且要小心避免阻塞UI线程,这意味着你需要在后台中执行各种操作。为了让这一过程变得更简单,我们增加了一个类叫做“Task”。一个Task代表一个异步操作。Task用于继续处理操作返回的结果,是由异步操作返回的。当一个Task被函数返回,它已经开始完成它的任务了。Task不与特定的线程模型进行绑定:它代表的是一个操作被完成,而不是一个操作正在被执行。Task与其他异步方法(例如AsyncTask)相比有许多优势。

(1)      Task占用更少的系统资源,因为Task在等待其他Tasks的时候不占用线程

(2)      执行一系列Task的时候不需要像你使用CallBack时一样写出金字塔式的嵌套代码。

(3)      Task是可以组合的,允许你执行分支、并行和复合型的错误处理,不需要用到嵌套的代码和各种复杂命名的CallBack.

(4)      你可以有序的整理你基于任务的代码并执行它们,而不是将你的逻辑分散在凌乱的回调函数中。

4、调用

我们知道,Bolts的核心是异步,那么与RxJava类似,我们可以决定我们的代码应该运行在UI线程,还是当前线程,还是后台线程,因此Task类中定义了几种线程池,方便我们在使用这个框架的时候作为一个参数传进去实现在不同的线程中调用我们的代码,这几种线程池代码如下:

/**
    * An {@link java.util.concurrent.Executor} that executes tasks in parallel.
    */
  public static final ExecutorService BACKGROUND_EXECUTOR = BoltsExecutors.background();

  /**
   * An {@link java.util.concurrent.Executor} that executes tasks in the current thread unless
   * the stack runs too deep, at which point it will delegate to {@link Task#BACKGROUND_EXECUTOR} in
   * order to trim the stack.
   */
  private static final Executor IMMEDIATE_EXECUTOR = BoltsExecutors.immediate();

  /**
   * An {@link java.util.concurrent.Executor} that executes tasks on the UI thread.
   */
  public static final Executor UI_THREAD_EXECUTOR = AndroidExecutors.uiThread();

BACKGROUND_EXECUTOR  是运行在后台线程。

IMMEDIATE_EXECUTOR按照我的理解是运行在当前线程(这个我不确定,因为没用到过因此没有测试,但是应该没错)

UI_THREAD_EXECUTOR 是运行在UI线程(即主线程)

了解了这几个线程池的差别后,我们就可以开始使用Bolts来运行我们的代码了,下面的代码中的getImageFromWeb()方法是一个从网上下载一张图片并保存在全局变量bitmap中的方法,具体实现忽略。

(1)运行一个单个任务

Task.call(new Callable<Bitmap>() {
        @Override
        public Bitmap call() throws Exception {//这里可以返回空值,把返回类型设为Void即可,返回其他类型的用法将在下面提到
            //你要执行的代码
	    Bitmap bitmap = getImageFromWeb();
            return <span style="font-family: Arial, Helvetica, sans-serif;">bitmap</span><span style="font-family: Arial, Helvetica, sans-serif;">;    //这里返回的bitmap将在下面讲到的任务执行结果中</span>
        }
    }, Task.BACKGROUND_EXECUTOR);//这里的参数可以参考上面填入别的线程池,控制这段代码在哪个线程运行

(2)“continueWith”方法

每一个Task都有一个方法叫做continueWith并且它带有一个参数Continuation。Continuation是一个你需要实现的接口,你需要实现它的方法then。Then方法会在Task完成后被调用,你可以通过这个方法来检查Task是否成功以及获得它的结果。

Task.call(new Callable<Bitmap>() {
            @Override
            public Bitmap call() throws Exception {//这里可以返回空值,把返回类型设为Void即可,返回其他类型的用法将在下面提到
                //你要执行的代码
                Bitmap bitmap = getImageFromWeb();
                return bitmap;    //这里返回的bitmap将在下面讲到的任务执行结果处理中
            }
        }, Task.BACKGROUND_EXECUTOR)//在后台线程中运行
                .continueWith(new Continuation<Bitmap, Void>() {
                    @Override
                    public Void then(Task<Bitmap> task) throws Exception {
                        // set ui
                        if (task.isFaulted()) {
                        Exception exc = task.getError();//图片加载失败,进行错误处理
                        } else if (task.isCompleted()) {
                            //图片加载成功
                            setImage(task.getResult());//task.getResult()是获取上面执行任务成功后返回结果的方法
                        }
                        return null;
                    }
                }, Task.UI_THREAD_EXECUTOR);//在UI线程中运行

(3)如果我们只需要关心上一个任务执行成功才要进行处理,那么我们可以用.onSuccess方法来代替.continueWith方法,具体用法如下:

Task.call(new Callable<Bitmap>() {
            @Override
            public Bitmap call() throws Exception {//需要返回一个Bitmap
                //你要执行的代码
                Bitmap bitmap = getImageFromWeb();
                return bitmap;    //这里返回的bitmap将在下面讲到的任务执行结果中
            }
        }, Task.BACKGROUND_EXECUTOR)//后台线程运行
                .onSuccess(new Continuation<Bitmap, Object>() {

                    @Override
                    public Void then(Task<Bitmap> task) throws Exception {
                            //图片加载成功
                            setImage(task.getResult());//将图片显示出来
                        return null;
                    }
                }, Task.UI_THREAD_EXECUTOR);//主线程运行

(4)在知道如何使用上面的两种方法之后,我们就可以运用它们来执行一个顺序任务了,下面的示例代码中需要执行三个任务,执行任务1成功后,才会执行任务2,而任务2不论成功失败都会在任务3中进行处理。

Task.call(new Callable<Bitmap>() {
            @Override
            public Bitmap call() throws Exception {
                //你要执行的代码,任务1
                Bitmap bitmap = getImageFromWeb();
                return bitmap;    //这里返回的bitmap将在下面讲到的任务执行结果中
            }
        }, Task.BACKGROUND_EXECUTOR)//后台线程运行
                .onSuccess(new Continuation<Bitmap, Bitmap>() {

                    @Override
                    public Bitmap then(Task<Bitmap> task) throws Exception {
                            //do something,任务2
                        Bitmap b = task.getResult();
                        return b;
                    }
                }, Task.BACKGROUND_EXECUTOR) //后台线程运行
                .continueWith(new Continuation<Bitmap, Void>() {
                    @Override
                    public Void then(Task<Bitmap> task) throws Exception {
                        // 任务3
                        if (task.isFaulted()) {
                            //图片加载失败,进行错误处理
                        } else if (task.isCompleted()) {
                            //图片加载成功
                            setImage(task.getResult());
                        }
                        return null;
                    }
                }, Task.UI_THREAD_EXECUTOR);//主线程运行

(5)除了顺序执行任务,我们还可以并行执行任务,下面的代码中,任务1创建了任务2和任务3用于并列执行,当两个任务都执行结束的时候会调用任务4进行结果处理。

Task.call(new Callable<List<Task<Bitmap>>>() {
            @Override
            public List<Task<Bitmap>> call() throws Exception {
                List<Task<Bitmap>> tasks = new ArrayList<Task<Bitmap>>();
                Task<Bitmap> task1 = Task.call(new Callable<Bitmap>() {
                    @Override
                    public Bitmap call() throws Exception {
                        // 任务2
                        return getImageFromWeb();
                    }
                }, Task.BACKGROUND_EXECUTOR);

                Task<Bitmap> task2 = Task.call(new Callable<Bitmap>() {
                    @Override
                    public Bitmap call() throws Exception {
                        // 任务3
                        return getImageFromWeb();
                    }
                }, Task.BACKGROUND_EXECUTOR);
                tasks.add(task1);
                tasks.add(task2);
                Task.whenAll(tasks).waitForCompletion();
                return tasks;    //这里返回的
            }
        }, Task.BACKGROUND_EXECUTOR)//后台线程运行
                .continueWith(new Continuation<List<Task<Bitmap>>, Void>() {
                    @Override
                    public Void then(Task<List<Task<Bitmap>>> task) throws Exception {
                        // 任务4
                        if (task.isFaulted()) {
                            //进行错误处理
                            Exception exception = task.getError();
                        } else if (task.isCompleted()) {
                            //取出两个并列执行的Task,获取执行结束的返回值
                            for(Task<Bitmap> t:task.getResult()){
                                if(t.isCompleted()){
                                    //task执行成功
                                    setImage(t.getResult());
                                }
                            }
                        }
                        return null;
                    }
                }, Task.UI_THREAD_EXECUTOR);//主线程运行

(6)task执行continueWith之前还可以进行延时,只需要在调用continueWith之前调用.delay(time)即可。

时间: 2024-10-12 13:46:27

Bolts框架在安卓中的简单应用的相关文章

用CI框架向数据库中实现简单的增删改查

以下代码基于CodeIgniter_2.1.3版 用PHP向数据库中实现简单的增删改查(纯代码)请戳 http://www.cnblogs.com/corvoh/p/4641476.html CodeIgniter_2.1.3与PHP5.6的兼容问题请戳 http://www.cnblogs.com/corvoh/p/4649357.html 增: //insert//语法:$bool=$this->db->insert('表名',关联数组); $data=array( 'username'=

安卓中的数据存储方式以及ContentProvider的简单介绍

1.介绍android的数据存储方式 File存储 sharedPrefrence存储方式 conmtentprovider sqlitedatabase 网络存储 2.请介绍下ContentProvider是如何实现数据共享的 安卓中如果想将自己应用程序的数据暴露给其他的应用程序的时候就需要创建内容提供者.第三方可以通过contentResolver来访问该provider 3.为什么要使用ContentProvider?它和sql的实现上有什么差别? ContentProvider屏蔽了数据

安卓中Service详解

service(服务)是安卓中的四大组件之一,它通常用作在后台处理耗时的逻辑,与Activity一样,它存在自己的生命周期,也需要在清单文件中配置相关信息,本博客将对Service的各个知识点进行详细讲解. 一Service的基本用法: 1使用本地服务 1)服务的启动方式 1通过Context的startService()方法启动服务:以该方法启动的服务,开启该服务的应用组件(如Activity)与该Service不存在关联关系,即使开启该服务的Activity被销毁,Service任能够一直在

使用junit框架对安卓应用进行单元测试 20150412

我的上一篇博客http://www.cnblogs.com/wushaobo/p/4396308.html,开发了一个简单安卓app闰年测试.在这里,使用junit框架对这个app进行简单的单元测试. 为了方便进行测试,我将程序做了简单的修改,将toast提示改为页面文本,添加回车事件响应闰年判断.效果如下: 1.测试准备 在实际开发中,开发android软件的过程需要不断地进行测试.而使用Junit测试框架,则是正规Android开发的必用技术. 测试使用eclipse + ADT +andr

安卓中的内存泄漏

因为安卓是基于java语言的,所以我们先来看一看java中的内存泄漏,然后在此基础上来谈谈安卓中的内存泄漏. 一java中的内存泄漏: java中的内存泄漏主要是指在堆中分配的内存,明明已经不需要的时候,还仍然保留着访问它的引用,导致GC回收不能及时回收(关于GC回收不做过多赘述),导致这种情况出现的最主要原因是长生命周期的对象持有短生命周期对象的引用,导致短生命周期的对象明明已经不需要却无法被GC回收,从而导致内存泄漏.主要包括以下几种情况: 1在一个类中创建了一个非静态内部类的静态实例,如下

WPF Step By Step 系列-Prism框架在项目中使用

WPF Step By Step 系列-Prism框架在项目中使用 回顾 上一篇,我们介绍了关于控件模板的用法,本节我们将继续说明WPF更加实用的内容,在大型的项目中如何使用Prism框架,并给予Prism框架来构建基础的应用框架,并且如何来设计项目的架构和模块,下面我们就来一步步开始吧. 本文大纲 1.Prism框架下载和说明 2.Prism项目预览及简单介绍. 3.Prism框架如何在项目中使用. Prism框架下载和说明 Prism框架是针对WPF和Silverlight的MVVM框架,这

安卓中实现界面数据懒加载

大家在使用手机新闻客户端的时候就会有一个发现,大多数的新闻客户端都会把新闻分类,诸如头条.娱乐.体育.科技等等,如何实现这种界面的呢?这个实现起来其实很简单,就是在一个Fragment中实现多个ViewPage的切换,再在ViewPage的上面放一个TabLayout,关联起来就可以实现联动效果.如果大家感觉不太明了的话,以后我可以专门写一篇关于Fragment中放入多个ViewPage的博客,今天,我主要介绍的是怎样实现界面即Fragment的懒加载.那么,大家就会奇怪了既然是加载界面直接加载

安卓中的事件分发机制源码解析

安卓中的事件分发机制主要涉及到两类控件,一类是容器类控件ViewGroup,如常用的布局控件,另一类是显示类控件,即该控件中不能用来容纳其它控件,它只能用来显示一些资源内容,如Button,ImageView等控件.暂且称前一类控件为ViewGroup类控件(尽管ViewGroup本身也是一个View),后者为View类控件. 安卓中的事件分发机制主要涉及到dispatchTouchEvent(MotionEvent ev).onInterceptTouchEvent(MotionEvent e

【SSH进阶之路】一步步重构容器实现Spring框架——彻底封装,实现简单灵活的Spring框架(十一)

目录 [SSH进阶之路]一步步重构容器实现Spring框架--从一个简单的容器开始(八) [SSH进阶之路]一步步重构容器实现Spring框架--解决容器对组件的"侵入式"管理的两种方案--主动查找和控制反转(九) [SSH进阶之路]一步步重构容器实现Spring框架--配置文件+反射实现IoC容器(十) [SSH进阶之路]一步步重构容器实现Spring框架--彻底封装,实现简单灵活的Spring框架(十一) 博文[SSH进阶之路]一步步重构容器实现Spring框架--从一个简单的容器