EventBus的使用详解

1.EventBus是什么?

     EventBus是一种在Android中高效的发布/订阅的事件总线机制,主要作用是可以替代传统的Handler, intent, BroadCast在Activity, Fragment,sevice,线程之间传递数据 ,而且代码实现得更优雅,实现了发布者(Publisher)和接受者(Subcribler)的完美解耦。

2.EventBus的基本用法

1.下载EventBus库,链接地址:https://github.com/greenrobot/EventBus/releases
2.将下载好的EventBus-2.4.0.jar复制在自己工程的libs目录中
3.新建一个自定义类,用于区分事件和传递数据(我这里是MsgEvent1,MsgEvent2,MsgEvent3)
由于类代码重复,这里只贴出MsgEvent1
/**
 * Created by zhangxing on 2016/10/21.
 */

public class MsgEvent1 {

        private String msg;

        public MsgEvent1(String msg) {
            super();
            this.msg = msg;
        }

        public String getMsg() {
            return msg;
        }
    }
很简单吧,申明一个带参放的构造方法,用于接收数据,通过getMsg()方法取出数据,就是这么简单哦!
4.新建MainActivity,我在activity_main中申明两个fragment(leftFragment,rightFragment)
public class MainActivity extends FragmentActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}
activity_main.xml:
xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:divider="?android:attr/dividerHorizontal"
    android:orientation="horizontal"
    android:showDividers="middle"
    android:baselineAligned="false"
     >

            android:id="@+id/left_fragment"
        android:name="hongda.zhangxing.com.eventbardemo.fragment.LeftFragment"
        android:layout_width="0dip"
        android:layout_height="match_parent"
        android:layout_weight="2" />

            android:id="@+id/right_fragment"
        android:name="hongda.zhangxing.com.eventbardemo.fragment.RightFragment"
        android:layout_width="0dip"
        android:layout_height="match_parent"
        android:layout_weight="3" />

很清晰的明白,主界面由两个fragment组成。
5.leftFragment代码:(发布者)
public class LeftFragment extends ListFragment {

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        String[] strs = new String[]{"主线程消息1", "子线程消息1", "主线程消息2"};
        setListAdapter(new ArrayAdapter(getActivity(), R.layout.item_list, strs));
    }

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        switch (position) {
            case 0:
                // 主线程
                System.out.println("我是主线程发送的消息1,小牧");
                EventBus.getDefault().post(new MsgEvent1("主线程发的消息1"));
                break;
            case 1:
                // 子线程
                new Thread(){
                    public void run() {
                        System.out.println("我是子线程发送的消息1,小星");
                        EventBus.getDefault().post(new MsgEvent1("子线程发的消息1"));
                    };
                }.start();

                break;
            case 2:
                // 主线程
                System.out.println("我是主线程发送的消息2,小皮");
                EventBus.getDefault().post(new MsgEvent2("主线程发的消息2"));
                break;
        }
    }

}
这里的leftFragment通过EventBus.getDefault().post()被定义为EventBus的发布者,post()中装载参数类型,这里很关键,到后面就知道了,跟着我走哈,别分心!
6.那么rightFragment在搞么事?
public class RightFragment extends Fragment {
    private TextView tv;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 界面创建时,订阅事件, 接受消息
       EventBus.getDefault().register(this);
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        // 界面销毁时,取消订阅
        EventBus.getDefault().unregister(this);
    }
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // 布局只有一个TextView,不再贴代码
        View view = inflater.inflate(R.layout.fragment_right, null);
        tv = (TextView) view.findViewById(R.id.tv);
        return view;
    }

    /**
     * 与发布者在同一个线程
     * @param msg 事件1
     */
    public void onEvent(MsgEvent1 msg){
        String content = msg.getMsg()
                + "\n ThreadName: " + Thread.currentThread().getName()
                + "\n ThreadId: " + Thread.currentThread().getId();
        System.out.println("onEvent(MsgEvent1 msg)收到" + content);
    }

    /**
     * 执行在主线程。
     * 非常实用,可以在这里将子线程加载到的数据直接设置到界面中。
     * @param msg 事件1
     */
    public void onEventMainThread(MsgEvent1 msg){
        String content = msg.getMsg()
                + "\n ThreadName: " + Thread.currentThread().getName()
                + "\n ThreadId: " + Thread.currentThread().getId();
        System.out.println("onEventMainThread(MsgEvent1 msg)收到" + content);
        tv.setText(content);
    }

    /**
     * 执行在子线程,如果发布者是子线程则直接执行,如果发布者不是子线程,则创建一个再执行
     * 此处可能会有线程阻塞问题。
     * @param msg 事件1
     */
    public void onEventBackgroundThread(MsgEvent1 msg){
        String content = msg.getMsg()
                + "\n ThreadName: " + Thread.currentThread().getName()
                + "\n ThreadId: " + Thread.currentThread().getId();
        System.out.println("onEventBackgroundThread(MsgEvent1 msg)收到" + content);
    }

    /**
     * 执行在在一个新的子线程
     * 适用于多个线程任务处理, 内部有线程池管理。
     * @param msg 事件1
     */
    public void onEventAsync(MsgEvent1 msg){
        String content = msg.getMsg()
                + "\n ThreadName: " + Thread.currentThread().getName()
                + "\n ThreadId: " + Thread.currentThread().getId();
        System.out.println("onEventAsync(MsgEvent1 msg)收到" + content);
    }

    /**
     * 与发布者在同一个线程
     * @param msg 事件2
     */
    public void onEvent(MsgEvent2 msg){
        String content = msg.getMsg()
                + "\n ThreadName: " + Thread.currentThread().getName()
                + "\n ThreadId: " + Thread.currentThread().getId();
        System.out.println("onEvent(MsgEvent2 msg)收到" + content);
        tv.setText(content);
    }
}
嗦嘎,rightFragment通过onCreate()中的EventBus.getDefault().register(this)注册了EventBus,所以呢,他就被任命为了接受者,你注册了我,就要接受我的事件消息;有点像你既然娶了我,就要三千水,只取一瓢饮,对我负责!哈哈,我逗逼了一把,这里只是让各位更好的理解EventBus注册的真正用意。 好了,整个框架就算搭成功了,需求是点击左边的fragment的item,右边的fragment的界面也随之更新。
7.效果图:
EventBus的使用详解_第1张图片

EventBus的使用详解_第2张图片
文字不重要,看重点!

3.EventBus的进阶

有人也许耐不住性子了,锅锅,到底是怎么传递数据的啊,哈哈,小兄弟,消消气,馒头来了!
1.注册EventBus类中的函数解析
①onEvent:
如果使用onEvent作为订阅函数,那么该事件在哪个线程发布出来的,onEvent就会在这个线程中运行,也就是说发布事件和接收事件线程在同一个线程。使用这个方法时,在onEvent方法中不能执行耗时操作,如果执行耗时操作容易导致事件分发延迟。
/**
 * 与发布者在同一个线程
 * @param msg 事件2
 */
public void onEvent(MsgEvent2 msg){
    String content = msg.getMsg()
            + "\n ThreadName: " + Thread.currentThread().getName()
            + "\n ThreadId: " + Thread.currentThread().getId();
    System.out.println("onEvent(MsgEvent2 msg)收到" + content);
    tv.setText(content);
}

②onEventMainThread :
如果使用onEventMainThread作为订阅函数,那么不论事件是在哪个线程中发布出来的,onEventMainThread都会在UI线程中执行,接收事件就会在UI线程中运行,这个在Android中是非常有用的,因为在Android中只能在UI线程中跟新UI,所以在onEvnetMainThread方法中是不能执行耗时操作的。
/**
 * 执行在主线程。
 * 非常实用,可以在这里将子线程加载到的数据直接设置到界面中。
 * @param msg 事件1
 */
public void onEventMainThread(MsgEvent1 msg){
    String content = msg.getMsg()
            + "\n ThreadName: " + Thread.currentThread().getName()
            + "\n ThreadId: " + Thread.currentThread().getId();
    System.out.println("onEventMainThread(MsgEvent1 msg)收到" + content);
    tv.setText(content);
}

③onEventBackground:
如果使用onEventBackgrond作为订阅函数,那么如果事件是在UI线程中发布出来的,那么onEventBackground就会在子线程中运行,如果事件本来就是子线程中发布出来的,那么onEventBackground函数直接在该子线程中执行。
/**
 * 执行在子线程,如果发布者是子线程则直接执行,如果发布者不是子线程,则创建一个再执行
 * 此处可能会有线程阻塞问题。
 * @param msg 事件1
 */
public void onEventBackgroundThread(MsgEvent1 msg){
    String content = msg.getMsg()
            + "\n ThreadName: " + Thread.currentThread().getName()
            + "\n ThreadId: " + Thread.currentThread().getId();
    System.out.println("onEventBackgroundThread(MsgEvent1 msg)收到" + content);
}

④onEventAsync:
使用这个函数作为订阅函数,那么无论事件在哪个线程发布,都会创建新的子线程在执行onEventAsync.
/**
 * 执行在在一个新的子线程
 * 适用于多个线程任务处理, 内部有线程池管理。
 * @param msg 事件1
 */
public void onEventAsync(MsgEvent1 msg){
    String content = msg.getMsg()
            + "\n ThreadName: " + Thread.currentThread().getName()
            + "\n ThreadId: " + Thread.currentThread().getId();
    System.out.println("onEventAsync(MsgEvent1 msg)收到" + content);
}
我想这四个函数应该没问题吧!
2.到底具体怎样调用订阅函数,这是关键
调用原则:根据发布者调用post()方法时传入的参数类型,然后对应接收者的订阅函数的入参类型,对号入座,进行有目的性的调用。
这里我还是证实一下:
我将发布者的post()中的参数全部改成MsgEvent1的实例:
EventBus的使用详解_第3张图片

我将订阅函数onEvent()的入参传入MsgEvent1类型,目的只让它一个人接收发布者的信息:
EventBus的使用详解_第4张图片

我们来看看Logcat:见证奇迹的时刻来了!
EventBus的使用详解_第5张图片

EventBus的使用详解_第6张图片

是不是?哈哈,我猜的对吧!好了,今天的EventBus就告一段落,有什么问题私信我,我是张星,欢迎您的关注,后期更精彩!!





你可能感兴趣的:(android)