Android 中 EventBus 的使用(3):多线程事件处理

在这一系列教程的最后一篇中,我想谈谈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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

SomeActivity.java:

...

@Inject EventBus bus;

...

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

...

button.setOnClickListener(new View.OnClickListener() {

public void onClick(View v) {

eventBus.post(new DoOperationEvent());

}

});

}

@Override

protected void onResume() {

super.onResume();

bus.register(this);

}

@Override

protected void onPause() {

bus.unregister(this);

super.onPause();

}

public void onEventMainThread(OperationCompleteEvent event) {

Toast.makeText(this, "Operation complete!", Toast.LENGTH_SHORT).show();

}

...

SomeService.java:

...

@Inject EventBus bus;

...

@Override

protected void onCreate() {

super.onCreate();

bus.register(this);

}

@Override

protected void onDestroy() {

bus.unregister(this);

super.onDestroy();

}

public void onEventAsync(DoOperationEvent event){

// DO SOMETHING LONG-RUNNING HERE

eventBus.post(new OperationCompleteEvent());

}

...

尽管这个例子比较简单,但它却非常简明扼要地说明了问题。这里即不需要实现监听接口,也不会出现类似生命周期之类的问题(由于activity只能在它存在的时候才能接收到OperationCompleteEvent事件)。除此之外,如果发生了配置改变(旋转屏幕)或其他什么原因导致activity在两次事件发生之间被销毁并重建,最终仍可以接收到OperationCompleteEvent事件。

此外,我们也可以容易地想到一些其它用法。比如,如果需要将更新进度发出去,你只需另外实现一个封装了进度值的事件类,然后将其发送出去即可。或者,如果你想让其它一些事件(不管是相同还是不同类型)不被并行处理(同步执行),你可以选择使用onEventBackgroundThread。

依赖Bus

实例化EventBus最简单的方法就是通过EventBus.getDefault()。然而,在EventBusBuilder类(通过EventBus.builder()获得)中还包含了另外一些有用的配置方法。特别是在本文中提到过的使用你自己的ExecutorService。缺省情况下EventBus通过Executors.newCachedThreadPool()创建自己的ExecutorService,在大多数情况下都已满足你的需要。然而,有时你可能仍然想要显示地控制EventBus所使用的线程数量,这种情况下你就可以象下面这样初始化EventBus:

Java

1

EventBus.builder().executorService(Executors.newFixedTheadPool(NUM_THREADS)).installDefaultEventBus();

在EventBusBuilder中另外一些可供配置的是一些和异常处理的有关的控制,以及一个是否允许事件类被继承的控制开关。这些内容超出了本文所讨论的范围,但我还是建议你仔细去研究一番。GR可能并没有把这些内容都写在文档里,但如果你读一读EventBusBuilder和EventBus的源代码,相信你会很容易理解它们的。

全能程序员交流QQ群290551701,聚集很多互联网精英,技术总监,架构师,项目经理!开源技术研究,欢迎业内人士,大牛及新手有志于从事IT行业人员进入!

时间: 2024-10-10 00:29:07

Android 中 EventBus 的使用(3):多线程事件处理的相关文章

Android 中 EventBus 的使用(2):缓存事件

在上一篇文章中,我曾提到我所选择的是Green Robot提供的EventBus(Android平台),而且这并非只是我一个人的选择.在最近一次查看中,我发现选择它的人数已经是Otto(由Jake Wharton和其他大神们在Square上所提供的版本)的两倍之多了.GR的版本显然比Otto有更多的性能提升,但最令我动心的地方在于它添加了很多新功能.今天我就打算谈谈其中的一项:通过sticky事件进行事件缓存. sticky是什么? sticky事件就是指在EventBus内部被缓存的那些事件.

Android中的几种多线程实现

有以下几种方式: 1)Activity.runOnUiThread(Runnable) 2)View.post(Runnable) ;View.postDelay(Runnable , long) 3)Handler 4)AsyncTask Android是单线程模型,这意味着Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行,所以你单纯的new一个Thread并且start()是不行的,因为这违背了Android的单线程模型.那么如何用好多线程呢?总结一下: 事件处理的原

EventBus在Android中的简单使用

EventBus是一个方便与Android中各组件通信的开源框架,开源地址;https://github.com/greenrobot/EventBus.EventBus功能非常强大 ,今天在做一个功能时.遇到了点击事件的冲突问题及数据传递更新问题. 详细点就是在能够上下拉刷新的ListView的Header上有GridView.此时,GridView的OnitemClick事件与ListView的OnItemClick事件冲突. 并且我在实现 Griview的点击事件时,还要进行数据传递. 解

Android中的事件分发机制(下)——View的事件处理

综述 在上篇文章Android中的事件分发机制(上)--ViewGroup的事件分发中,对ViewGroup的事件分发进行了详细的分析.在文章的最后ViewGroup的dispatchTouchEvent方法调用dispatchTransformedTouchEvent方法成功将事件传递给ViewGroup的子View.并交由子View进行处理.那么现在就来分析一下子View接收到事件以后是如何处理的. View的事件处理 对于这里描述的View,它是ViewGroup的父类,并不包含任何的子元

Android中多线程编程(四)AsyncTask类的详细解释(附源码)

Android中多线程编程中AsyncTask类的详细解释 1.Android单线程模型 2.耗时操作放在非主线程中执行 Android主线程和子线程之间的通信封装类:AsyncTask类 1.子线程中更新UI 2.封装.简化异步操作. 3.AsyncTask机制:底层是通过线程池来工作的,当一个线程没有执行完毕,后边的线程是无法执行的.必须等前边的线程执行完毕后,后边的线程才能执行. AsyncTask类使用注意事项: 1.在UI线程中创建AsyncTask的实例 2.必须在UI线程中调用As

Android中使用多线程的各种姿势

写在前面:内容主要为黄岳钊老师视频分享课的学习笔记. 1)为什么需要多线程处理? 解决耗时任务 文件IO.联网请求.数据库操作.RPC 提高并发能力 同一时间处理更多事情 防止ANR InputDispatching Timeout:输入事件分发超时5s(触摸或按键) Service Timeout:服务20s内未执行完 BroadcastQueue Timeout:前台广播10s内未执行完 ContentProvider Timeout:内容提供者执行超时 避免掉帧 要达到每秒60帧,每帧必须

android中的多线程机制

Google参考了Windows的消息处理机制,在Android系统中实现了一套类似的消息处理机制.学习Android的消息处理机制,有几个概念(类)必须了解: 1.       Message 消息,理解为线程间通讯的数据单元.例如后台线程在处理数据完毕后需要更新UI,则可发送一条包含更新信息的Message给UI线程. 2.       Message Queue 消息队列,用来存放通过Handler发布的消息,按照先进先出执行. 3.       Handler Handler是Messa

转载:android笔记--android中的多线程--Handler, Looper, MessageQueue, Message类

什么时候使用多线程: 1. 耗时操作使用多线程, 耗时操作放在UI线程中会导致用户的操作无法得到响应. 2. 阻塞操作使用多线程, 理由同上. 3. 多核CUP的设备使用多线程, 可以有效提高CPU的利用率. 4. 并行操作使用多线程. android中的多线程模型主要涉及的类有:Looper, Handler, MessageQueue, Message等. 一:Looper类: 1 static final ThreadLocal<Looper> sThreadLocal = new Th

Android中的多线程编程(一)附源代码

Android中多线程编程:Handler类.Runnable类.Thread类之概念分析 1.Handler类: Handler是谷歌封装的一种机制:能够用来更新UI以及消息的发送和处理.Handler是执行在主线程(UI线程). (2).使用Handler机制的原因: 这是谷歌封装的一种更新UI机制和消息机制.假设不使用这个来更新UI和发送处理消息的时候就会抛出异常. (3).Handler的使用: Handler发送消息事实上是发送给自己.也就是说由自己来进行发送和处理.是由于Handle