欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android 中 EventBus 的使用之多线程事件处理

程序员文章站 2023-12-15 10:10:28
在这一系列教程的最后一篇中,我想谈谈gr的eventbus,在处理多线程异步任务时是多么简单而有效。 asynctask, loader和executor…… 拜托!...

在这一系列教程的最后一篇中,我想谈谈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的源代码,相信你会很容易理解它们的。

上一篇:

下一篇: