EventBus的应用

EventBus是GreenRobot开发的Android和Java的开源库,使用发布者/订阅者模式进行解耦合。EventBus使组件之间的通信只需几行代码即可搞定,极度解耦并且简化了代码,消除依赖关系并加快应用程序开发。这里是EventBus的官网: https://greenrobot.org/eventbus/ 。在介绍EventBus的通信方法之前,首先会介绍常规的通信方法,比如说设置监听或者是使用广播等方式,以此来说明常规的方法都有其弊端,然后使用EventBus来完成组件之间的通信,通过案例体会EventBus在组件通信过程中的优势。

GreenRobot组织开发的这款开源库,从这个项目的名称就充分体现了它的功能,EventBus有两个单词组成——Event和Bus。那什么是Event呢?在Android平台上有非常多的事件类型,其中最常见的就是触控事件,当触控事件发生的时候,应用程序需要做出一些响应,从而来和用户进行交互。应用程序的各个组件之间以及应用程序和用户之间都需要进行通信。有了消息通信,应用程序才是可交互的。那接下来的问题就是如何进行通信呢?也就是说如何去发送和处理消息呢?

在回答这个问题之前,我们先来看一下什么叫做Bus。现在请调整思维,脱离软件开发领域,进入到日常生活场景。我们经常需要从一个地方到达另外一个地方,比如说出发地是上海。目的地是杭州。一开始我们位于出发地,如果靠自己的双脚走路。你知道路线就是一个不小的挑战。通常情况下,我们会借助公共交通系统,有了这样的运输系统,我们就只需要做两件事儿:第一件事儿就是从出发地上车;第二件事儿就是在目的地下车。整个运输过程当中,这个交通系统对我们来说是不可见的,我们并不需要了解其内部细节。只需要做两件事儿,第一件就是从出发地上车,第二件就是在目的地下车。

那现在我们回到软件开发领域,这次我们需要运输的对象不再是自己。而是事件消息,这个事件有一个发送方,具体来说它就会是某一个Java类当中的某一个方法,我们是在这个方法中来发送消息。那还有一个订阅方,订阅方就是表示我对这个事件感兴趣。我要接收这个事件消息,我要处理这个事件消息,借助EventBus这个运输系统。我们需要做两件事儿,第一件事儿就是在这个发送方去发布消息,然后EventBus的运输系统就会来负责在内部来传递这个消息。对于我们需要关注的第二件事儿,就是在订阅方来以订阅和处理这个事件。整个过程当中EventBus就是一个黑盒子,我们只需要做两件事儿。第一件事儿就是发布事件,第二件事儿就是订阅和处理事件。这次应该EventBus已经有了一个初步的认识,它就是一个能够帮助我们完成组件间通信的工具。需要掌握如何使用EventBus完成事件的订阅和发布,从而借助这样的一个开源库轻松的实现组件间的相互通信。

常规通信方法

在介绍这些方式之前,先介绍一下项目Demo的功能,

Listener监听的方式

MainActivity.java

 1public class MainActivity extends AppCompatActivity {
 2    private static final String TAG = "MainActivity";
 3    private ImageView ivEmoji;
 4    @Override
 5    protected void onCreate(Bundle savedInstanceState) {
 6        super.onCreate(savedInstanceState);
 7        setContentView(R.layout.activity_main);
 8        ivEmoji = findViewById(R.id.iv_emoji);
 9    }
10
11    public void showDialogFragment(View view) {
12        // Display DialogFragment
13        PublisherDialogFragment fragment = new PublisherDialogFragment();
14        fragment.show(getSupportFragmentManager(), "publisher");
15        fragment.setEventListener(new PublisherDialogFragment.OnEventListener() {
16            @Override
17            public void onSuccess() {
18                ivEmoji.setImageResource(R.drawable.ic_happy);
19            }
20
21            @Override
22            public void onFailed() {
23                ivEmoji.setImageResource(R.drawable.ic_bad);
24            }
25        });
26    }
27}

activity_main.xml 布局文件

 1<?xml version="1.0" encoding="utf-8"?>
 2<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3    xmlns:tools="http://schemas.android.com/tools"
 4    android:layout_width="match_parent"
 5    android:layout_height="match_parent"
 6    tools:context=".MainActivity">
 7
 8
 9    <ImageView
10        android:id="@+id/iv_emoji"
11        android:layout_centerInParent="true"
12        android:layout_width="200dp"
13        android:layout_height="200dp"/>
14
15    <Button
16        android:layout_width="50dp"
17        android:layout_height="50dp"
18        android:layout_alignParentBottom="true"
19        android:layout_alignParentEnd="true"
20        android:layout_marginBottom="20dp"
21        android:layout_marginEnd="20dp"
22        android:onClick="showDialogFragment"
23        android:background="@drawable/ic_add"
24        />
25
26</RelativeLayout>

PublisherDialogFragment.java

 1public class PublisherDialogFragment extends DialogFragment {
 2    private static final String TAG = "PublisherDialogFragment";
 3
 4    private OnEventListener onEventListener;
 5    @NonNull
 6    @Override
 7    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
 8        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
 9        builder.setTitle("Publisher");
10        String[] items = new String[]{"Success", "Failed"};
11        builder.setItems(items, (dialog, which) -> {
12            switch (which){
13                case 0: // Success
14                    onEventListener.onSuccess();
15                    break;
16                case 1: // Failed
17                    onEventListener.onFailed();
18                    break;
19                default:
20                    break;
21            }
22        });
23        return builder.create();
24    }
25
26    public interface OnEventListener{
27        void onSuccess();
28        void onFailed();
29    }
30
31    public void setEventListener(OnEventListener listener){
32        this.onEventListener = listener;
33    }
34}

这样做虽然实现了功能,但是耦合性还是比较高的,对于事件的发布方必须定义接口,而且当时间越来越多的时候我们就需要定义越来越多的接口和方法,这样事件的接收方和发送方耦合在了一起,当两个组件中存在依赖的时候,耦合关系就建立了,其中一个修改的话就会影响到另外一个组件,耦合度过高是不利于软件开发的,所以还有什么其他的通信方式呢?接下来看看本地广播这种形式。

本地广播的方式

为什么使用本地广播呢?因为只是在这个应用内部进行通信,其他App不需要监听这个广播,所以采用本地广播即可: MainActivity中注册广播监听,注意在Activity销毁时取消广播监听,MainActivity.java:

 1......
 2import androidx.localbroadcastmanager.content.LocalBroadcastManager;
 3
 4public class MainActivity extends AppCompatActivity {
 5    private static final String TAG = "MainActivity";
 6    private ImageView ivEmoji;
 7
 8    public static final String HAND_EVENT_ACTION = "hand_event_action";;
 9    public static final String result = "result";
10    private LocalBroadcastManager broadcastManager;
11
12    BroadcastReceiver receiver = new BroadcastReceiver() {
13        @Override
14        public void onReceive(Context context, Intent intent) {
15            if(intent.getAction().equals(HAND_EVENT_ACTION)){
16                if(intent.getBooleanExtra(result, false)){
17                    ivEmoji.setImageResource(R.drawable.ic_happy);
18                }else {
19                    ivEmoji.setImageResource(R.drawable.ic_bad);
20                }
21            }
22        }
23    };
24
25    @Override
26    protected void onCreate(Bundle savedInstanceState) {
27        super.onCreate(savedInstanceState);
28        setContentView(R.layout.activity_main);
29        ivEmoji = findViewById(R.id.iv_emoji);
30        broadcastManager = LocalBroadcastManager.getInstance(this);
31    }
32
33    @Override
34    protected void onStart() {
35        super.onStart();
36
37        IntentFilter filter = new IntentFilter(HAND_EVENT_ACTION);
38        broadcastManager.registerReceiver(receiver, filter);
39    }
40
41    @Override
42    protected void onStop() {
43        super.onStop();
44        broadcastManager.unregisterReceiver(receiver);
45    }
46
47    public void showDialogFragment(View view) {
48        // Display DialogFragment
49        PublisherDialogFragment fragment = new PublisherDialogFragment();
50        fragment.show(getSupportFragmentManager(), "publisher");
51    }
52}

PublisherDialogFragment.java

 1......
 2import androidx.localbroadcastmanager.content.LocalBroadcastManager;
 3
 4public class PublisherDialogFragment extends DialogFragment {
 5    private static final String TAG = "PublisherDialogFragment";
 6
 7    @NonNull
 8    @Override
 9    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
10        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
11        builder.setTitle("Publisher");
12        String[] items = new String[]{"Success", "Failed"};
13        builder.setItems(items, (dialog, which) -> {
14            Intent intent = new Intent(MainActivity.HAND_EVENT_ACTION);
15            switch (which){
16                case 0: // Success
17                    intent.putExtra(MainActivity.result, true);
18                    LocalBroadcastManager.getInstance(getActivity())
19                            .sendBroadcast(intent);
20                    break;
21                case 1: // Failed
22                    intent.putExtra(MainActivity.result, false);
23                    LocalBroadcastManager.getInstance(getActivity())
24                            .sendBroadcast(intent);
25                    break;
26                default:
27                    break;
28            }
29        });
30        return builder.create();
31    }
32}

对于广播通信的方式对于发送方需要创建Intent,并且双方必须规定好Intent的Action,而且必须规定好Intent中的数据字段。对于消息的接收方,又需要解析Intent中的数据,可以说还是比较麻烦了。而且广播都是运行在UI线程,如果想要在后台线程需要我们手动作切换,使用起来就不是很方便了。

使用EventBus通信

下面来直接使用EventBus进行组件之间的通信,也就是上面的例子,看看可以省略多少代码呢? 使用EventBus重点需要三步:定义事件 -> 在订阅方进行订阅 -> 发布方发布事件,首先需要引入依赖:

1implementation group: 'org.greenrobot', name: 'eventbus', version: '3.1.1'

定义一个事件,其实就是一个普通的Java类:

 1public class MyEvent {
 2    private boolean result;
 3
 4    public MyEvent(boolean result) {
 5        this.result = result;
 6    }
 7
 8    public boolean isResult() {
 9        return result;
10    }
11
12    public void setResult(boolean result) {
13        this.result = result;
14    }
15}

MainActivity.java中订阅事件:

 1import org.greenrobot.eventbus.EventBus;
 2import org.greenrobot.eventbus.Subscribe;
 3
 4public class MainActivity extends AppCompatActivity {
 5    private ImageView ivEmoji;
 6
 7    @Override
 8    protected void onStart() {
 9        super.onStart();
10        EventBus.getDefault().register(this);
11    }
12
13    @Override
14    protected void onStop() {
15        super.onStop();
16        EventBus.getDefault().unregister(this);
17    }
18
19    @Subscribe
20    public void onEvent(MyEvent myEvent){
21        if(myEvent.isResult()){
22            ivEmoji.setImageResource(R.drawable.ic_happy);
23        }else {
24            ivEmoji.setImageResource(R.drawable.ic_bad);
25        }
26    }
27
28    @Override
29    protected void onCreate(Bundle savedInstanceState) {
30        super.onCreate(savedInstanceState);
31        setContentView(R.layout.activity_main);
32        ivEmoji = findViewById(R.id.iv_emoji);
33    }
34
35    public void showDialogFragment(View view) {
36        // Display DialogFragment
37        PublisherDialogFragment fragment = new PublisherDialogFragment();
38        fragment.show(getSupportFragmentManager(), "publisher");
39    }
40}

PublisherDialogFragment.java作为发布方发布事件:

 1public class PublisherDialogFragment extends DialogFragment {
 2
 3    @NonNull
 4    @Override
 5    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
 6        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
 7        builder.setTitle("Publisher");
 8        String[] items = new String[]{"Success", "Failed"};
 9        builder.setItems(items, (dialog, which) -> {
10            switch (which){
11                case 0: // Success
12                    EventBus.getDefault().post(new MyEvent(true));
13                    break;
14                case 1: // Failed
15                    EventBus.getDefault().post(new MyEvent(false));
16                    break;
17                default:
18                    break;
19            }
20        });
21        return builder.create();
22    }
23}

EventBus线程模式

EventBus3.0有四种线程模型,分别是: 1、POSTING:默认模式,表示事件处理函数的线程跟发布事件的线程在同一个线程。 2、MAIN:表示事件处理函数的线程在主线程(UI)线程,因此在这里不能进行耗时操作。 3、BACKGROUND:表示事件处理函数的线程在后台线程,因此不能进行UI操作。如果发布事件的线程是主线程(UI线程),那么事件处理函数将会开启一个后台线程,如果果发布事件的线程是在后台线程,那么事件处理函数就使用该线程。 4、ASYNC:表示无论事件发布的线程是哪一个,事件处理函数始终会新建一个子线程运行,同样不能进行UI操作。

POSTING模式

POSTING模式是EventBus默认的模式,我们在使用的时候不需要再订阅者的方法的注解后面添加模式选项,但是这种只能在同一个线程中接收,也就是说,如果是在主线程中发布消息就只能在主线程中接收消息,如果是在子线程中,那么也只能在相同的子线程中去接收消息,在下面的例子中,演示的是50%的随机几率在新线程发送事件,50%的随机几率在UI线程发送事件。

订阅者代码:(MainActivity.java)

1// POSTING 模式
2@Subscribe(threadMode = ThreadMode.POSTING)
3public void onPostingEvent(final PostingEvent event){
4    String threadInfo = Thread.currentThread().toString();
5    runOnUiThread(()->{
6        setPublisherThreadInfo(event.threadInfo);
7        setSubscriberThreadInfo(threadInfo);
8    });
9}

发布者代码:(PublisherDialogFragment.java)

 1if(Math.random() > 0.5f){
 2    new Thread("002"){
 3        @Override
 4        public void run() {
 5            EventBus.getDefault().post(new PostingEvent(Thread.currentThread().toString()));
 6        }
 7    }.start();
 8}else {
 9    EventBus.getDefault().post(new PostingEvent(Thread.currentThread().toString()));
10}

MAIN模式

MAIN模式保证了订阅者指定的那个接收方法肯定要主线程中执行,可以放心的在里面执行更新UI操作。无论发布者是在主线程中还是在那一条子线程中发布消息,这边接收的都在主线程中。

订阅者代码:(MainActivity.java)

1// MAIN 模式
2@Subscribe(threadMode = ThreadMode.MAIN)
3public void onMainEvent(final MainEvent event){
4    String threadInfo = Thread.currentThread().toString();
5    runOnUiThread(()->{
6        setPublisherThreadInfo(event.threadInfo);
7        setSubscriberThreadInfo(threadInfo);
8    });
9}

发布者代码:(PublisherDialogFragment.java)

 1if(Math.random() > 0.5f){
 2    new Thread("002"){
 3        @Override
 4        public void run() {
 5            EventBus.getDefault().post(new MainEvent(Thread.currentThread().toString()));
 6        }
 7    }.start();
 8}else {
 9    EventBus.getDefault().post(new MainEvent(Thread.currentThread().toString()));
10}

MAIN_ORDER模式

MAIN_ORDER模式与MAIN模式类似,但是稍微有点区别:MAIN_ORDER模式和MAIN一样都是在主线程中,不同的就是不需要等带订阅方完成订阅,发布方就可以继续自己的代码运行:

订阅者代码:(MainActivity.java)

 1// MAIN_ORDER 模式
 2@Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
 3public void onMainOrderEvent(final MainOrderEvent event){
 4    Log.i(TAG, "onMainOrderEvent: enter @" + SystemClock.uptimeMillis());
 5    setPublisherThreadInfo(event.threadInfo);
 6    setSubscriberThreadInfo(Thread.currentThread().toString());
 7    try {
 8        TimeUnit.SECONDS.sleep(1);
 9    } catch (InterruptedException e) {
10        e.printStackTrace();
11    }
12    Log.i(TAG, "onMainOrderEvent: exit @" + SystemClock.uptimeMillis());
13}

发布者代码:(PublisherDialogFragment.java)

1Log.i(TAG, "onCreateDialog: before @" + SystemClock.uptimeMillis());
2EventBus.getDefault().post(new MainOrderEvent(Thread.currentThread().toString()));
3Log.i(TAG, "onCreateDialog: after @" + SystemClock.uptimeMillis());

同样的代码当使用MAIN模式时:(即@Subscribe(threadMode = ThreadMode.MAIN)):

同样的代码当使用MAIN_ORDER模式时:(即@Subscribe(threadMode = ThreadMode.MAIN_ORDER)):

BACKGROUND

订阅者代码:(MainActivity.java)

1// BACKGROUND 模式
2@Subscribe(threadMode = ThreadMode.BACKGROUND)
3public void onBackgroundEvent(final MainOrderEvent event){
4    final String threadInfo = Thread.currentThread().toString();
5    runOnUiThread(()->{
6        setPublisherThreadInfo(event.threadInfo);
7        setSubscriberThreadInfo(threadInfo);
8    });
9}

发布者代码:(PublisherDialogFragment.java)

 1if(Math.random() > 0.5f){
 2    new Thread("002"){
 3        @Override
 4        public void run() {
 5            EventBus.getDefault().post(new BackgroundEvent(Thread.currentThread().toString()));
 6        }
 7    }.start();
 8}else {
 9    EventBus.getDefault().post(new BackgroundEvent(Thread.currentThread().toString()));
10}

ASYNC

表示无论事件发布的线程是哪一个,事件处理函数始终会新建一个子线程运行,同样不能进行UI操作: 订阅者代码:(MainActivity.java)

1// ASYNC 模式
2@Subscribe(threadMode = ThreadMode.ASYNC)
3public void onAsyncEvent(final AsyncEvent event){
4    final String threadInfo = Thread.currentThread().toString();
5    runOnUiThread(()->{
6        setPublisherThreadInfo(event.threadInfo);
7        setSubscriberThreadInfo(threadInfo);
8    });
9}

发布者代码:(PublisherDialogFragment.java)

 1if(Math.random() > 0.5f){
 2    new Thread("002"){
 3        @Override
 4        public void run() {
 5            EventBus.getDefault().post(new AsyncEvent(Thread.currentThread().toString()));
 6        }
 7    }.start();
 8}else {
 9    EventBus.getDefault().post(new AsyncEvent(Thread.currentThread().toString()));
10}
11break;

下面是整个工程全部的代码:

 1public class MainActivity extends AppCompatActivity {
 2    private static final String TAG = "MainActivity";
 3    @Override
 4    protected void onCreate(Bundle savedInstanceState) {
 5        super.onCreate(savedInstanceState);
 6        setContentView(R.layout.activity_main);
 7        setTitle("Subscriber");
 8    }
 9
10    @Override
11    protected void onStart() {
12        super.onStart();
13        EventBus.getDefault().register(this);
14    }
15
16    @Override
17    protected void onStop() {
18        super.onStop();
19        EventBus.getDefault().unregister(this);
20    }
21
22    // POSTING 模式
23    @Subscribe(threadMode = ThreadMode.POSTING)
24    public void onPostingEvent(final PostingEvent event){
25        String threadInfo = Thread.currentThread().toString();
26        runOnUiThread(()->{
27            setPublisherThreadInfo(event.threadInfo);
28            setSubscriberThreadInfo(threadInfo);
29        });
30    }
31
32    // MAIN 模式
33    @Subscribe(threadMode = ThreadMode.MAIN)
34    public void onMainEvent(final MainEvent event){
35        String threadInfo = Thread.currentThread().toString();
36        runOnUiThread(()->{
37            setPublisherThreadInfo(event.threadInfo);
38            setSubscriberThreadInfo(threadInfo);
39        });
40    }
41
42    // MAIN_ORDER 模式
43    @Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
44    public void onMainOrderEvent(final MainOrderEvent event){
45        Log.i(TAG, "onMainOrderEvent: enter @" + SystemClock.uptimeMillis());
46        setPublisherThreadInfo(event.threadInfo);
47        setSubscriberThreadInfo(Thread.currentThread().toString());
48        try {
49            TimeUnit.SECONDS.sleep(1);
50        } catch (InterruptedException e) {
51            e.printStackTrace();
52        }
53        Log.i(TAG, "onMainOrderEvent: exit @" + SystemClock.uptimeMillis());
54    }
55
56    // BACKGROUND 模式
57    @Subscribe(threadMode = ThreadMode.BACKGROUND)
58    public void onBackgroundEvent(final BackgroundEvent event){
59        final String threadInfo = Thread.currentThread().toString();
60        runOnUiThread(()->{
61            setPublisherThreadInfo(event.threadInfo);
62            setSubscriberThreadInfo(threadInfo);
63        });
64    }
65
66    // ASYNC 模式
67    @Subscribe(threadMode = ThreadMode.ASYNC)
68    public void onAsyncEvent(final AsyncEvent event){
69        final String threadInfo = Thread.currentThread().toString();
70        runOnUiThread(()->{
71            setPublisherThreadInfo(event.threadInfo);
72            setSubscriberThreadInfo(threadInfo);
73        });
74    }
75
76    private void setPublisherThreadInfo(String threadInfo){
77        setTextView(R.id.tv_publisher_thread, threadInfo);
78    }
79
80    private void setSubscriberThreadInfo(String threadInfo){
81        setTextView(R.id.tv_subscriber_thread, threadInfo);
82    }
83
84    // Run on UI Thread
85    private void setTextView(int resId, String text){
86        TextView textView = findViewById(resId);
87        textView.setText(text);
88        textView.setAlpha(0.5f);
89        textView.animate().alpha(1).start();
90    }
91
92    public void showDialogFragment(View view) {
93        // Display DialogFragment
94        PublisherDialogFragment fragment = new PublisherDialogFragment();
95        fragment.show(getSupportFragmentManager(), "publisher");
96    }
97}

PublisherDialogFragment.java

 1public class PublisherDialogFragment extends DialogFragment {
 2    private static final String TAG = "PublisherDialogFragment";
 3    @NonNull
 4    @Override
 5    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
 6        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
 7        builder.setTitle("Publisher");
 8        String[] items = new String[]{"Posting", "Main", "MainOrder", "Background", "Async"};
 9        builder.setItems(items, (dialog, which) -> {
10            switch (which){
11                case 0: // Posting Mode
12                    if(Math.random() > 0.5f){
13                        new Thread("002"){
14                            @Override
15                            public void run() {
16                                EventBus.getDefault().post(new PostingEvent(Thread.currentThread().toString()));
17                            }
18                        }.start();
19                    }else {
20                        EventBus.getDefault().post(new PostingEvent(Thread.currentThread().toString()));
21                    }
22                    break;
23                case 1: // Main Mode
24                    if(Math.random() > 0.5f){
25                        new Thread("002"){
26                            @Override
27                            public void run() {
28                                EventBus.getDefault().post(new MainEvent(Thread.currentThread().toString()));
29                            }
30                        }.start();
31                    }else {
32                        EventBus.getDefault().post(new MainEvent(Thread.currentThread().toString()));
33                    }
34                    break;
35
36                case 2: // Main_Order Mode
37                    Log.i(TAG, "onCreateDialog: before @" + SystemClock.uptimeMillis());
38                    EventBus.getDefault().post(new MainOrderEvent(Thread.currentThread().toString()));
39                    Log.i(TAG, "onCreateDialog: after @" + SystemClock.uptimeMillis());
40                    break;
41
42                case 3: // BACKGROUND Mode
43                    if(Math.random() > 0.5f){
44                        new Thread("002"){
45                            @Override
46                            public void run() {
47                                EventBus.getDefault().post(new BackgroundEvent(Thread.currentThread().toString()));
48                            }
49                        }.start();
50                    }else {
51                        EventBus.getDefault().post(new BackgroundEvent(Thread.currentThread().toString()));
52                    }
53                    break;
54
55                case 4: // ASYNC Mode
56                    if(Math.random() > 0.5f){
57                        new Thread("002"){
58                            @Override
59                            public void run() {
60                                EventBus.getDefault().post(new AsyncEvent(Thread.currentThread().toString()));
61                            }
62                        }.start();
63                    }else {
64                        EventBus.getDefault().post(new AsyncEvent(Thread.currentThread().toString()));
65                    }
66                    break;
67                default:
68                    break;
69            }
70        });
71        return builder.create();
72    }
73}

activity_main.xml

 1<?xml version="1.0" encoding="utf-8"?>
 2<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3    xmlns:tools="http://schemas.android.com/tools"
 4    android:layout_width="match_parent"
 5    android:layout_height="match_parent"
 6    tools:context=".MainActivity">
 7
 8
 9    <ImageView
10        android:id="@+id/iv_emoji"
11        android:layout_centerInParent="true"
12        android:layout_width="200dp"
13        android:layout_height="200dp"/>
14
15    <LinearLayout
16        android:orientation="vertical"
17        android:layout_width="wrap_content"
18        android:layout_centerInParent="true"
19        android:layout_height="wrap_content">
20
21        <TextView
22            android:layout_width="wrap_content"
23            android:layout_height="wrap_content"
24            android:text="Publisher:"/>
25
26        <TextView
27            android:id="@+id/tv_publisher_thread"
28            android:textColor="#00f"
29            android:textSize="20sp"
30            android:layout_width="wrap_content"
31            android:layout_height="wrap_content"/>
32
33        <TextView
34            android:layout_width="wrap_content"
35            android:layout_height="wrap_content"
36            android:text="Subscriber:"/>
37
38        <TextView
39            android:id="@+id/tv_subscriber_thread"
40            android:textColor="#f00"
41            android:textSize="20sp"
42            android:layout_width="wrap_content"
43            android:layout_height="wrap_content"/>
44    </LinearLayout>
45
46    <Button
47        android:layout_width="50dp"
48        android:layout_height="50dp"
49        android:layout_alignParentBottom="true"
50        android:layout_alignParentEnd="true"
51        android:layout_marginBottom="20dp"
52        android:layout_marginEnd="20dp"
53        android:onClick="showDialogFragment"
54        android:background="@drawable/ic_add"
55        />
56</RelativeLayout>

以上的内容就是EventBus的基本使用方法与线程模式的总结了。

参考资料

1、 EventBus: Events for Android

2、 维基百科——发布/订阅