文章目录
  1. 1. EventBus使用详解
    1. 1.1. EventBus使用步骤
      1. 1.1.1. (1)引入EventBus:
      2. 1.1.2. (2)定义一个消息类,该类可以不继承任何基类也不需要实现任何接口。如:
      3. 1.1.3. (3)在需要订阅事件的地方注册事件
      4. 1.1.4. (4)发送事件:即发送消息
      5. 1.1.5. (5)处理消息
        1. 1.1.5.1. EventBus3.0与EventBus2.4的区别
      6. 1.1.6. (6)取消消息订阅
      7. 1.1.7. (7)代码混淆
  2. 2. 事件的优先级处理
  3. 3. EventBus粘性事件
  4. 4. 取消订阅事件
  5. 5. 注意:

你还在为刷新ui伤透脑筋吗?你还在琢磨如何使用接口回调或者handle来实现吗?如果你想到了使用观察者模式,那么一个很屌的Android开源框架EventBus:主要功能是替代Intent、Handler、BroadCast在Fragment、Activity、Service、线程之间传递消息。他的最牛逼优点是开销小,代码简洁,解耦代码。

如果你没有使用过eventBus那么很遗憾你错过了很多,不过没有关系3.0的正式发布,使用没有什么大不一样只是性能更好。

个人建议直接使用3.0.0的版本,也不要去使用2.4和3.0beta1的版本了

看图说话:

EventBus是一款针对Android优化的发布/订阅(publish/subscribe)事件总线。

EventBus作为一个消息总线,有三个主要的元素:

  • Event:事件。可以是任意类型的对象
  • Subscriber:事件订阅者,接收特定的事件。在EventBus中,使用约定来指定事件订阅者以简化使用。即所有事件订阅都都是以onEvent开头的函数,具体来说,函数的名字是onEvent,onEventMainThread,onEventBackgroundThread,onEventAsync这四个,这个和

ThreadMode(下面讲)有关。

  • Publisher:事件发布者,用于通知 Subscriber 有事件发生。可以在任意线程任意位置发送事件,直接调用eventBus.post(Object) 方法,可以自己实例化 EventBus

对象,但一般使用默认的单例就好了:EventBus.getDefault(), 根据post函数参数的类型,会自动调用订阅相应类型事件的函数。

EventBus使用详解

EventBus使用步骤

(1)引入EventBus:
  • 引入eventbus:2.4.0(回顾老版本)

compile ‘de.greenrobot:eventbus:2.4.0’

  • 引入eventbus:3.0.0-beta1

compile ‘de.greenrobot:eventbus:3.0.0-beta1’

  • 引入eventbus:3.0.0

compile ‘org.greenrobot:eventbus:3.0.0’

(2)定义一个消息类,该类可以不继承任何基类也不需要实现任何接口。如:
1
2
3
4
5
6
public class MessageEvent {
    ......
}
(3)在需要订阅事件的地方注册事件

EventBus.getDefault().register(this);

(4)发送事件:即发送消息

EventBus.getDefault().post(messageEvent);

(5)处理消息

在3.0之前,EventBus还没有使用注解方式。消息处理的方法也只能限定于onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,分别代表四种线程模型。而在3.0之后,消息处理的方法可以随便取名,但是需要添加一个注解@Subscribe,并且要指定线程模型(beta1默认为PostThread,正式版默认为POSTING),四种线程模型,下面会讲到。

注意,事件处理函数的访问权限必须为public,否则会报异常。

EventBus3.0与EventBus2.4的区别
  • EventBus 2.4在使用方式
1
2
3
4
5
6
 public void onEvent(MessageEvent event) {
// 事件在哪个线程发布出来的,onEvent就会在这个线程中运行,也就是说发布事件和接收事件线程在同一个线程。使用这个方法时,在onEvent方法中不能执行耗时操作,如果执行耗时操作容易导致事件分发延迟。
    }
1
2
3
4
5
6
 public void onEventMainThread(MessageEvent event) {
// 不论事件是在哪个线程中发布出来的,onEventMainThread都会在UI线程中执行,接收事件就会在UI线程中运行,这个在Android中是非常有用的,因为在Android中只能在UI线程中跟新UI,所以在onEvnetMainThread方法中是不能执行耗时操作的。
    }
1
2
3
4
5
6
public void onEventBackgroundThread(MessageEvent event){
//那么如果事件是在UI线程中发布出来的,那么onEventBackground就会在子线程中运行,如果事件本来就是子线程中发布出来的,那么onEventBackground函数直接在该子线程中执行。
    }
1
2
3
4
5
6
public void onEventAsync(MessageEvent event){
//使用这个函数作为订阅函数,那么无论事件在哪个线程发布,都会创建新的子线程在执行onEventAsync.
    }
  • 在EventBus 3.0.0的使用是这样的

(1) beta1版的写法

1
2
3
4
5
6
7
8
  @Subscribe(threadMode = ThreadMode.PostThread) //3.0.0-beta1
    public void onMessageEventPost(UserEvent event) {
    //默认方式, 在发送线程执行
    }
1
2
3
4
5
6
7
8
 @Subscribe(threadMode = ThreadMode.MainThread) 
    public void onMessageEventMain(UserEvent event) {
    //在ui线程执行
    }
1
2
3
4
5
6
7
8
   @Subscribe(threadMode = ThreadMode.BackgroundThread)
    public void onMessageEventBackground(UserEvent event) {
     //在后台线程执行
    }
1
2
3
4
5
6
7
8
 @Subscribe(threadMode = ThreadMode.Async) 
    public void onMessageEventAsync(UserEvent event) {
    //强制在后台执行
    }

(2) 正式版的写法

1
2
3
4
5
6
7
8
  @Subscribe(threadMode = ThreadMode.POSTING) //3.0.0
    public void onMessageEventPost(UserEvent event) {
    //默认方式, 在发送线程执行
    }
1
2
3
4
5
6
7
8
 @Subscribe(threadMode = ThreadMode.MAIN) 
    public void onMessageEventMain(UserEvent event) {
    //在ui线程执行
    }
1
2
3
4
5
6
7
8
   @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void onMessageEventBackground(UserEvent event) {
     //在后台线程执行
    }
1
2
3
4
5
6
7
8
 @Subscribe(threadMode = ThreadMode.ASYNC) 
    public void onMessageEventAsync(UserEvent event) {
    //强制在后台执行
    }
(6)取消消息订阅

EventBus.getDefault().unregister(this);

(7)代码混淆
1
2
3
4
5
6
7
8
-keepclassmembers class ** {
    public void onEvent*(**);
    void onEvent*(**);
 }

看下简单实现的效果(带妹子的手机桌面):

看下具体的代码使用:

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
package com.losileeya.eventbusapp;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.losileeya.eventbusapp.event.EventBusEvents;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private Button btn_first,btn_second,btn_third,btn_sticky;
    private TextView tv_toast;
    private TextView tv_default,tv_main,tv_background,tv_asy;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        EventBus.getDefault().register(this);
        btn_first = (Button) findViewById(R.id.btn_first);
        btn_second = (Button) findViewById(R.id.btn_second);
        btn_third = (Button) findViewById(R.id.btn_third);
        btn_sticky= (Button) findViewById(R.id.btn_sticky);
        tv_toast= (TextView) findViewById(R.id.tv_toast);
        tv_default= (TextView) findViewById(R.id.tv_default);
        tv_main= (TextView) findViewById(R.id.tv_main);
        tv_background= (TextView) findViewById(R.id.tv_background);
        tv_asy= (TextView) findViewById(R.id.tv_asy);
        btn_first.setOnClickListener(this);
        btn_second.setOnClickListener(this);
        btn_third.setOnClickListener(this);
        btn_sticky.setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
        Intent intent;
        switch (v.getId()){
            case R.id.btn_first:
                intent = new Intent(MainActivity.this,FirstActivity.class);
                startActivity(intent);
                break;
            case R.id.btn_second:
                intent = new Intent(MainActivity.this,SecondActivity.class);
                startActivity(intent);
                break;
            case R.id.btn_third:
                intent = new Intent(MainActivity.this,ThirdActivity.class);
                startActivity(intent);
                break;
            case R.id.btn_sticky:
                intent = new Intent(MainActivity.this,StickyActivity.class);
                startActivity(intent);
                break;
        }
    }
    @Subscribe(threadMode = ThreadMode.MAIN,priority = 1)
    public void onMessageMain(EventBusEvents.FirstEvent firstEvent){
        tv_toast.setText(firstEvent.getValue());
        Toast.makeText(this, firstEvent.getValue(),Toast.LENGTH_SHORT).show();
        Log.e("zy", "onEventMainThread-->" +"priority = 1,"+ Thread.currentThread().getId());
        tv_main.setText(Thread.currentThread().getName()+"---->"+Thread.currentThread().getId());
    }
    /**
     * 使用onEvent来接收事件,那么接收事件和分发事件在一个线程中执行
     * param event
     */
    @Subscribe(threadMode = ThreadMode.POSTING,priority = 2)
    public void onPost(EventBusEvents.FirstEvent firstEvent) {
        Log.e("zy", "onEventPost-->" +"priority = 2,"+ Thread.currentThread().getId());
        tv_default.setText(Thread.currentThread().getName()+"---->"+Thread.currentThread().getId());
    }
    /**
     * 使用onEventBackgroundThread来接收事件,如果分发事件在子线程运行,那么接收事件直接在同样线程
     * 运行,如果分发事件在UI线程,那么会启动一个子线程运行接收事件
     * param event
     */
    @Subscribe(threadMode = ThreadMode.BACKGROUND,priority = 3)
    public void onBackgroundThread(EventBusEvents.FirstEvent firstEvent)
    {
        Log.e("zy", "onEventBackgroundThread-->" +"priority = 3,"+ Thread.currentThread().getId());
        tv_background.setText(Thread.currentThread().getName()+"---->"+Thread.currentThread().getId());
    }
    /**
     * 使用onEventAsync接收事件,无论分发事件在(UI或者子线程)哪个线程执行,接收都会在另外一个子线程执行
     * param event
     */
    @Subscribe(threadMode = ThreadMode.ASYNC,priority = 4)
    public void onAsync(EventBusEvents.FirstEvent firstEvent) {
        Log.e("zy", "onEventAsync-->"+"priority = 4," + Thread.currentThread().getId());
        tv_asy.setText(Thread.currentThread().getName()+"---->"+Thread.currentThread().getId());
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }
}
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package com.losileeya.eventbusapp;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import com.losileeya.eventbusapp.event.EventBusEvents;
import org.greenrobot.eventbus.EventBus;
public class FirstActivity extends AppCompatActivity {
    private Button btn_showDownLoad;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first);
        btn_showDownLoad = (Button) findViewById(R.id.btn_toast);
        btn_showDownLoad.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        EventBus.getDefault().post(new EventBusEvents.FirstEvent("我是从网络下载的文本"));
                    }
                }).start();
            }
        });
    }
}

可以看出哪里需要发送消息,那么就必须使用:

EventBus.getDefault().post(your event)

然后你只需要订阅就好了:

1
2
3
4
5
6
7
8
9
10
   @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageMain(EventBusEvents.FirstEvent firstEvent){
        tv_toast.setText(firstEvent.getValue());
        Toast.makeText(this, firstEvent.getValue(),Toast.LENGTH_SHORT).show();
    }

事件的优先级处理

接收事件方法可以通过@Subscribe(priority = 1)

priority的值来决定接收事件的顺序,数值越高优先级越大,默认优先级为0.

(注意这里优先级设置只有在同一个线程模型才有效)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
   @Subscribe(threadMode = ThreadMode.ASYNC,priority = 4)
    public void onAsync(EventBusEvents.FirstEvent firstEvent) {
        Log.e("zy", "onEventAsync-->"+"priority = 4," + Thread.currentThread().getId());
        tv_asy.setText(Thread.currentThread().getName()+"---->"+Thread.currentThread().getId());
    }
    @Subscribe(threadMode = ThreadMode.ASYNC,priority = 2)
    public void onAsync1(EventBusEvents.FirstEvent firstEvent) {
        Log.e("zy", "onEventAsync1-->"+"priority = 2," + Thread.currentThread().getId());
        tv_asy.setText(Thread.currentThread().getName()+"---->"+Thread.currentThread().getId());
    }

同一模式下优先级高的先执行,看图:

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
  @Subscribe(threadMode = ThreadMode.MAIN,priority = 1)
    public void onMessageMain(EventBusEvents.FirstEvent firstEvent){
        tv_toast.setText(firstEvent.getValue());
        Toast.makeText(this, firstEvent.getValue(),Toast.LENGTH_SHORT).show();
        Log.e("zy", "onEventMainThread-->" +"priority = 1,"+ Thread.currentThread().getId());
        tv_main.setText(Thread.currentThread().getName()+"---->"+Thread.currentThread().getId());
    }
    /**
     * 使用onEvent来接收事件,那么接收事件和分发事件在一个线程中执行
     * param event
     */
    @Subscribe(threadMode = ThreadMode.POSTING,priority = 2)
    public void onPost(EventBusEvents.FirstEvent firstEvent) {
        Log.e("zy", "onEventPost-->" +"priority = 2,"+ Thread.currentThread().getId());
        tv_default.setText(Thread.currentThread().getName()+"---->"+Thread.currentThread().getId());
    }
    /**
     * 使用onEventBackgroundThread来接收事件,如果分发事件在子线程运行,那么接收事件直接在同样线程
     * 运行,如果分发事件在UI线程,那么会启动一个子线程运行接收事件
     * param event
     */
    @Subscribe(threadMode = ThreadMode.BACKGROUND,priority = 3)
    public void onBackgroundThread(EventBusEvents.FirstEvent firstEvent)
    {
        Log.e("zy", "onEventBackgroundThread-->" +"priority = 3,"+ Thread.currentThread().getId());
        tv_background.setText(Thread.currentThread().getName()+"---->"+Thread.currentThread().getId());
    }
    /**
     * 使用onEventAsync接收事件,无论分发事件在(UI或者子线程)哪个线程执行,接收都会在另外一个子线程执行
     * param event
     */
    @Subscribe(threadMode = ThreadMode.ASYNC,priority = 4)
    public void onAsync(EventBusEvents.FirstEvent firstEvent) {
        Log.e("zy", "onEventAsync-->"+"priority = 4," + Thread.currentThread().getId());
        tv_asy.setText(Thread.currentThread().getName()+"---->"+Thread.currentThread().getId());
    }

不同ThreadMode运行下结果看图:

事件优先级不影响不同线程模型订阅事件顺序.

EventBus粘性事件

除了上面讲的普通事件外,EventBus还支持发送黏性事件。简单讲,就是在发送事件之后再订阅该事件也能收到该事件.粘性事件能够收到订阅之前发送的消息。但是它只能收到最新的一次消息,比如说在未订阅之前已经发送了多条黏性消息了,然后再订阅只能收到最近的一条消息。

注册和注销方法一样,发送事件和订阅事件有些区别

发送事件

1
2
EventBus.getDefault().postSticky(you event);

订阅粘性事件 默认sticky为false

1
2
3
4
5
6
7
8
@Subscribe(sticky = true)
    public void onPostThread(Event.Message msg) {
        .....
    }

看荔枝:

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package com.losileeya.eventbusapp;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
/**
 * Created  on 2016/4/14.
 */
public class StickyActivity extends AppCompatActivity {
    private int index = 0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sticky);
        Button bt_send = (Button) findViewById(R.id.bt_send);
        Button bt_regist = (Button) findViewById(R.id.bt_regist);
        Button bt_unregist = (Button) findViewById(R.id.bt_unregist);
        bt_send.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.i("zy", "POSTING---->" + index);
                EventBus.getDefault().postSticky("zy---->" + index++);
            }
        });
        bt_regist.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EventBus.getDefault().register(StickyActivity.this);
            }
        });
        bt_unregist.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EventBus.getDefault().unregister(StickyActivity.this);
            }
        });
    }
    @Subscribe(threadMode = ThreadMode.POSTING,sticky = true)
    public void onPostThread(String msg) {
        Log.i("zy", "onEventPostThread---->" + msg);
    }
    @Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
    public void onMainThread(String msg) {
        Log.i("zy", "onEventMainThread---->" + msg);
    }
    @Subscribe(threadMode = ThreadMode.BACKGROUND,sticky = true)
    public void onBackgroundThread(String msg) {
        Log.i("zy", "onEventBackgroundThread---->" + msg);
    }
    @Subscribe(threadMode = ThreadMode.ASYNC,sticky = true)
    public void onAsyncThread(String msg) {
        Log.i("zy", "onEventAsyncThread---->" +msg);
    }
}

activity_sticky.xml

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
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >
    <Button
        android:id="@+id/bt_send"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="发送事件" />
    <Button
        android:id="@+id/bt_regist"
        android:layout_marginTop="10dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="注册" />
    <Button
        android:id="@+id/bt_unregist"
        android:layout_marginTop="10dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="注销" />
</LinearLayout>

看我的执行步骤:

  • 首先在未订阅的情况下点击发送按钮发送一个黏性事件,然后点击订阅,打印如下: —>

  • 我们连续点击发送事件按钮发送黏性事件,然后再点击注册按钮订阅,打印结果如下:—>

是不是接到了最后一个事件。

取消订阅事件

你可以取消事件订阅通过调用cancelEventDelivery(Object event)方法,任何进一步的事件交付将被取消,后续用户不会接收到事件,但是该方法只有在ThreadMode.PostThread事件处理方法中调用才有效.

就讲到这里了》》》

注意:

  1. @Subscribe 下的方法必须为public

  2. postSticky()发送的粘性消息订阅时必须@Subscribe(sticky = true)否则接收不到

  3. 发送的event事件是object类

  4. @Subscribe(priority = 1) 使用时优先级默认为0,然后只有统一模式下设置优先级才有效果,自己看着合理使用

demo传送门:EventBusApp

觉得还不错的帮忙顶一下,大家相互学习一下,哈哈哈。


未经许可不得转载,转载请注明zilianliuxue的blog,本人保留所有版权。

文章目录
  1. 1. EventBus使用详解
    1. 1.1. EventBus使用步骤
      1. 1.1.1. (1)引入EventBus:
      2. 1.1.2. (2)定义一个消息类,该类可以不继承任何基类也不需要实现任何接口。如:
      3. 1.1.3. (3)在需要订阅事件的地方注册事件
      4. 1.1.4. (4)发送事件:即发送消息
      5. 1.1.5. (5)处理消息
        1. 1.1.5.1. EventBus3.0与EventBus2.4的区别
      6. 1.1.6. (6)取消消息订阅
      7. 1.1.7. (7)代码混淆
  2. 2. 事件的优先级处理
  3. 3. EventBus粘性事件
  4. 4. 取消订阅事件
  5. 5. 注意: