Android 中 EventBus 的使用之多线程事件处理
在这一系列教程的最后一篇中,我想谈谈gr的eventbus,在处理多线程异步任务时是多么简单而有效。
asynctask, loader和executor…… 拜托!
android中有很多种执行异步操作的方法(指平行于ui线程的)。asynctask对于用户来说是最简单的一种机制,并且只需要少量的设置代码即可。然而,它的使用是有局限的,正如android官方文档中所描述的:
asynctask被设计成为一个工具类,在它内部包含了thread和handler,但它本身并不是通用线程框架的一部分。asynctask应该尽可能地被用在执行一些较短的操作中(最多几秒)。如果你需要在线程中执行较长时间的任务,那么建议你直接使用java.util.concurrent包中提供的各种api,如executor、 threadpoolexecutor以及futuretask。
不过即便是执行短时间的操作也会带来一些问题,特别是在与activity/fragment生命周期有关的地方。由于asynctask会持续地运行下去(即使启动它们的activity/fragment已经被销毁了)。这样,一旦你在onpostexecute方法中试图对ui进行更新,那么最终将导致抛出一个illegalstateexception异常。
android 3.0中引入了loader api用来解决activity/fragment生命周期的问题(它们的确很有效)。loader api被设计成向activity/fragment中以异步方式加载数据。尽管加载数据是一种非常常见的异步操作,但并非唯一一种需要从ui线程中分开的操作。loader还需要在activity/fragment中实现另外一个监听接口。尽管这么做没有错,但我个人并不喜欢这种模式(我的意思是最终你的代码中会包含许多的回调函数,导致代码的可读性变得很差)。最后,activity和fragment也并非唯一需要对异步操作分线程的地方。例如如果在service里,你就不能访问loadermanager,所以最终你还是得使用asynctask或者java.util.concurrent。
java.util.concurrent包很不错,我在android和非android项目中都可以使用。不过使用时需要对其进行多一点儿配置和管理,不象asynctask那么简单。你需要对executorservice进行初始化,管理和监视它的生命周期,并且可能需要跟一些future对象打交道。
只要使用恰当,asynctask、 loader和executor都是非常有效的。但在复杂应用中,需要为每个任务选择合适的工具,最终你可能三种都会用到。这样你就得维护三种不同的处理并发的框架代码。
green robot来帮忙了!
gr的eventbus中内置了一个非常棒的并发处理机制。在监听类中,你可以实现4种不同类型的处理方法。当一个匹配事件被发送过来时,eventbus会根据不同的并发模型将事件发送到相应的处理方法中:
onevent(t event):运行在和被发送事件相同的线程中。
oneventmainthread(t event):运行在主(ui)线程中,不管事件从哪个线程中被发送过来。
oneventasync(t event):运行在单独的线程中,即非ui线程,也非发送事件的线程。
oneventbackgroundthread(t event):如果发送事件的线程不是ui线程,则运行在该线程中。如果发送事件的是ui线程,则它运行在由eventbus维护的一个单独的线程中。多个事件会同步地被这个单独的后台线程所处理。
这些方法功能强大而且使用简单。例如有一个比较耗时的操作(可能是网络调用,大量数据处理等),这一操作需要由ui上的行为来触发,并且当操作执行完毕后还需对ui进行更新。在这个例子中,ui行为即按钮点击,按钮在activity中,耗时操作在service中。我们可以按下面的方式来实现:
java
尽管这个例子比较简单,但它却非常简明扼要地说明了问题。这里即不需要实现监听接口,也不会出现类似生命周期之类的问题(由于activity只能在它存在的时候才能接收到operationcompleteevent事件)。除此之外,如果发生了配置改变(旋转屏幕)或其他什么原因导致activity在两次事件发生之间被销毁并重建,最终仍可以接收到operationcompleteevent事件。
此外,我们也可以容易地想到一些其它用法。比如,如果需要将更新进度发出去,你只需另外实现一个封装了进度值的事件类,然后将其发送出去即可。或者,如果你想让其它一些事件(不管是相同还是不同类型)不被并行处理(同步执行),你可以选择使用oneventbackgroundthread。
依赖bus
实例化eventbus最简单的方法就是通过eventbus.getdefault()。然而,在eventbusbuilder类(通过eventbus.builder()获得)中还包含了另外一些有用的配置方法。特别是在本文中提到过的使用你自己的executorservice。缺省情况下eventbus通过executors.newcachedthreadpool()创建自己的executorservice,在大多数情况下都已满足你的需要。然而,有时你可能仍然想要显示地控制eventbus所使用的线程数量,这种情况下你就可以象下面这样初始化eventbus:
java
eventbus.builder().executorservice(executors.newfixedtheadpool(num_threads)).installdefaulteventbus();
在eventbusbuilder中另外一些可供配置的是一些和异常处理的有关的控制,以及一个是否允许事件类被继承的控制开关。这些内容超出了本文所讨论的范围,但我还是建议你仔细去研究一番。gr可能并没有把这些内容都写在文档里,但如果你读一读eventbusbuilder和eventbus的源代码,相信你会很容易理解它们的。
上一篇: CDR制作康师傅经典奶茶包装图文教程
推荐阅读
-
android中处理各种触摸事件的方法浅谈
-
Android多线程处理机制中的Handler使用介绍
-
Android中父View和子view的点击事件处理问题探讨
-
Android编程中延后处理事件的方法小结
-
android中处理各种触摸事件的方法浅谈
-
Android多线程处理机制中的Handler使用介绍
-
Android开发中EventBus的基本使用方式
-
Android 入门第十讲02-广播(广播概述,使用方法(系统广播,自定义广播,两个activity之间的交互和传值),EventBus使用方法,数据传递,线程切换,Android的系统广播大全)
-
Android线程中Handle的使用讲解
-
10_Android中通过HttpUrlConnection访问网络,Handler和多线程使用,读取网络html代码并显示在界面上,ScrollView组件的使用_html/css_WEB-ITnose