eventbus的使用及解析

参考资料:http://blog.csdn.net/lmj623565791/article/details/40920453

简介

最终效果如下图所示:
图片倒了,将就看吧...

不同页面,不同进程要相互调用或者产生数据交换怎么办呢?

一般的做法:

  • 目录Fragment在onCreate中去开启线程去访问网络获取数据,获取完成以后,通过handler去更新界面;

  • 在目录的Fragment中提供一个接口,然后详细信息面板去注册这个接口,当发生点击时,去回调这个接口,让详细信息面板发生改变;

  • 广播、静态方法等等。

EventBus定义:是一个发布 / 订阅的事件总线。包含4个成分:发布者,订阅者,事件,总线:
来自鸿洋

使用方法

几个主要的方法:

  • EventBus.getDefault().register(this);//订阅事件
  • EventBus.getDefault().post(object);//发布事件
  • EventBus.getDefault().unregister(this);//取消订阅

代码学习:

MainActivity:

public class MainActivity extends FragmentActivity {
    private TextView txtData;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        txtData=(TextView) findViewById(R.id.txt_data);
        //注册eventBus
        EventBus.getDefault().register(this);
    }

    @Override
    protected void onDestroy() {
        // Unregister
        EventBus.getDefault().unregister(this);
        super.onDestroy();
    }

    /** List点击时会发送些事件,接收到事件后更新详情 */
    public void onEventMainThread(Item item) {
        if (item != null)
            txtData.setText(item.content);
    }

}

代码片中:

  • 在Activity的Oncreate()中订阅事件(注册);
  • 在Activity被销毁时取消订阅(反注册)
  • onEventMainThread订阅函数,接收list点击时发布的事件,将内容显示到界面

ItemListFragment:

@Override
    public void onViewCreated(View view, Bundle savedInstanceState)
    {
        super.onViewCreated(view, savedInstanceState);
        // 开启线程加载列表
        new Thread()
        {
            public void run()
            {
                try
                {
                    Thread.sleep(2000); // 模拟延时
                    // 发布事件,在后台线程发的事件
                    EventBus.getDefault().post(new ItemListEvent(Item.ITEMS));
                } catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            };
        }.start();
    }

    public void onEventMainThread(ItemListEvent event)
    {
        setListAdapter(new ArrayAdapter<Item>(getActivity(),
                android.R.layout.simple_list_item_activated_1,
                android.R.id.text1, event.getItems()));
    }

    @Override
    public void onListItemClick(ListView listView, View view, int position,
            long id)
    {
        super.onListItemClick(listView, view, position, id);
        EventBus.getDefault().post(getListView().getItemAtPosition(position));
    }

代码解析:

  • 在子线程中模拟从服务器端拉取数据,然后通过EventBus发布事件
  • onEventMainThread()订阅函数,接收子线程发布的事件,将列表内容通过适配器显示到界面
  • List的点击事件,通过EventBus发布事件

DetailFragment:

/** List点击时会发送些事件,接收到事件后更新详情 */
    public void onEventMainThread(Item item)
    {
        if (item != null)
            tvDetail.setText(item.content);
    }

在代码片中:

  • onEventMainThread订阅函数,接收列表的点击事件,将列表内容显示到新的fragment中

Item实体类:

public static List<Item> ITEMS = new ArrayList<Item>();
    static
    {
        // Add 6 sample items.
        addItem(new Item("1", "Item 1"));
        addItem(new Item("2", "Item 2"));
        addItem(new Item("3", "Item 3"));
        addItem(new Item("4", "Item 4"));
        addItem(new Item("5", "Item 5"));
        addItem(new Item("6", "Item 6"));
    }

    private static void addItem(Item item)
    {
        ITEMS.add(item);
    }

    public Item(String id, String content)
    {
        this.id = id;
        this.content = content;
    }

    @Override
    public String toString()
    {
        return content;
    }

代码解析:

  • Item实体类,列表的每一项,在列表的点击时间时作为发布事件的参数

Event实体类:

/** 列表加载事件 */
    public static class ItemListEvent
    {
        private List<Item> items;

        public ItemListEvent(List<Item> items)
        {
            this.items = items;
        }

        public List<Item> getItems()
        {
            return items;
        }
    }

代码解析:

  • Event实体类,在子线程数据加载完成时作为发布事件的参数

注意几个不同的订阅函数:

  • onEventMainThread代表这个方法会在UI线程执行;
  • onEventPostThread代表这个方法会在当前发布事件的线程执行;
  • BackgroundThread这个方法,如果在非UI线程发布的事件,则直接执行,和发布在同一个线程中。如果在UI线程发布的事件,则加入后台任务队列,使用线程池一个接一个调用;
  • Async 加入后台任务队列,使用线程池调用,注意没有BackgroundThread中一个接一个。

原理解析

Register方法:

private synchronized void register(Object subscriber, String methodName, boolean sticky, int priority) {  
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass(),  
                methodName);  
        for (SubscriberMethod subscriberMethod : subscriberMethods) {  
            subscribe(subscriber, subscriberMethod, sticky, priority);  
        }  
    } 

代码解析:

  • 调用内部类SubscriberMethodFinder的findSubscriberMethods方法,传入了subscriber的class,以及methodName,返回一个List;
    那么不用说,肯定是去遍历该类内部所有方法,然后根据methodName去匹配,匹配成功的封装成SubscriberMethod,最后返回一个list;
    本质上就是扫描了所有的方法,把匹配的方法最终保存在subscriptionsByEventType(Map,key:eventType ;
    value:CopyOnWriteArrayList )中;

post方法:

private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {  
        switch (subscription.subscriberMethod.threadMode) {  
        case PostThread:  
            invokeSubscriber(subscription, event);  //通过反射调用
            break;  
        case MainThread: 
              //省略部分代码  break;  
        case BackgroundThread:  
          //省略部分代码            break;  
        case Async:  
            asyncPoster.enqueue(subscription, event);  
            break;  
        default:  
        //省略部分代码  
        }  

代码解析:

  • register时,把方法存在subscriptionsByEventType;那么post肯定会去subscriptionsByEventType去取方法,然后调用。

总结:

register会把当前类中匹配的方法,存入一个map,而post会根据实参去map查找进行反射调用。可以说,就是在一个单例内部维持着一个map对象存储了一堆的方法;post无非就是根据参数去查找方法,进行反射调用。

优缺点:

  • 代码非常的优雅。耦合基本没有,简化事件流程,对于复杂的页面交互,多进程通信很有帮助;
  • 消耗更多内存,反射可能会效率低。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值