android平台中,EventBus研究学习

android平台中,EventBus研究学习

大家好,又见面了,我是全栈君。

         当一个Android应用功能越来越多的时候。app中各个部分之间通信。往往採用Observer的方式来进行,即注冊—-通知—-注销的方式运行 各类控件常常须要依据某个状态来更新显示内容。这样的场景常见的解决方案就是定义一个接口,须要关注该事件的控件来实现这个接口。 接口类:
      public interface OnChangedListener {
            void onDataChanged();
        }
       被观察者往往以例如以下形式实现:

public abstract class AbsHTTPRequest {
    private final WeakHashMap<OnChangedListener, Boolean> mListeners = new WeakHashMap<OnChangedListener, Boolean>();
    public interface OnChangedListener {
        void onDataChanged();
    }
    
    /*HTTP's response*/
    public abstract void onResponse();
    
    public final void addListener(OnChangedListener listener) {
        mListeners.put(listener, true);
    }

    public final void removeListener(OnChangedListener listener) {
        mListeners.remove(listener);
    }
    
    protected final void notifyDataChanged() {
        Set<OnChangedListener> keys = mListeners.keySet();
        if(keys != null) {
            Iterator<OnChangedListener> iterator = keys.iterator();
            while(iterator.hasNext()) {
                iterator.next().onDataChanged();
            }
        }
    }
}

    详细的主题角色( 被观察者)
,实现方式例如以下:

public class LoginRequest extends AbsHTTPRequest implements OnChangedListener{
	public void onResponse(){
		addListener(this);
		notifyDataChanged();
	}

	@Override
	public void onDataChanged() {
		// TODO Auto-generated method stub
		System.out.println("LoginRequest");
	}
}

   
  使用观察者模式有一个弊病就是部件之间的耦合度太高,全部的主题角色都须要实现同一个interface。

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同一时候监听某一个主题对象。

假设主题角色被注冊的observer越多。那么须要实现的interface也就越多,接口方法数量也就越多。
     怎样来进行解耦,让代码逻辑更清晰。可读性更强。是一个问题。

     在Android中也有一个类似功能的开源库EventBus。能够非常方便的帮助我们实现观察者模式,而且让各个组件之间的耦合性更低。

      关于EventBus的解说文章,网络业非常多,这里推荐一篇,解说比較具体的blog,http://www.cnblogs.com/angeldevil/p/3715934.html 
对EventBus的认识,不妨从demo入手。先易后难。

首先知道怎样使用,然后再深究源代码,才干循序渐进,吃透当中的设计理念。便于日后的代码调试和模块重构。关于demo,网上有非常多,能够自己去查收。

      EventBus的使用有4个步奏:
1.定义事件类型:
    public class MyEvent
2.注冊订阅者:
    EventBus.getDefault().register(this)
3.发送事件:
    EventBus.getDefault().post(new MyEvent())
4.接收事件,处理
     订阅者回调的函数。官方指导。函数名称以onEvent开头。

    在EventBus模块中,有几个重要的概念。了解了这几个概念后,也就不难懂了。

          Event:能够是随意类型的对象
          Subscriber:订阅者,接收特定的
          Publisher:公布者。用于通知Subscriber发送

          EventType:onEvent函数中的參数。表示事件对象,用户自己定义的。

          Subscriber:订阅源,即调用register注冊的对象,这个对象内包括onEvent成员函数。
SubscribMethod.javafinal class SubscriberMethod {    final Method method;  /*Method类型的method成员表示这个onEvent,即事件处理函数。

同一时候也包括订阅源*/ final ThreadMode threadMode; final Class<?> eventType; /*事件的对象,用户自己定义Object*/... ... ... ... ... ... ... ... ... ... ... ...}

Subscription.java

final class Subscription {
    final Object subscriber;  /*订阅源Subscriber,即调用register注冊的对象*/
    final SubscriberMethod subscriberMethod; /**/
    final int priority;
... ... ... ... ... ... ... ... ... ... ... ...
}
 
类EventBus中。有两个核心的成员
   /*EventType -> List<Subscription>,事件到订阅对象之间的映射*/
    private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
  /* Subscriber -> List<EventType>,订阅对象到它订阅的的全部事件的映射关系*/
    private final Map<Object, List<Class<?>>> typesBySubscriber;

   
  注冊流程:在调用register函数时,EventBus类有多个重载的register函数,可是作者更倾向于使用register(this);含有 多个參数的register函数中,明白标注了@deprecated,原创作者不建议使用。

从代码:

    public void register(Object subscriber) {
        register(subscriber, DEFAULT_METHOD_NAME, false, 0);
    }

能够观察到,全部重载的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);
        }
    }

      当中注冊函数register。默认參数DEFAULT_METHOD_NAME为函数名称”onEvent”,在java放射机制中,全部的事件处理函数名称 统一为“onEvent”,只參数不一致。onEvent的參数为用户自己定义的对象。

      
注冊时。使用SubscriberMethodFinder的对象,调用到findSubscriberMethods方法。获取到List<SubscriberMethod>。
     数组对象Method[],调用getMethods()方法, 获取的是类的全部共同拥有方法,这就包含自身的全部public方法。和从基类继承的、从接口实现的全部public方法。

这也是为啥,我们的onEvent函数,要定义为public方法的原因哦。

    在findSubscriberMethods函数中,进行如此频繁的遍历。就是为了找到List<SubscriberMethod>。

每个订阅者,相应一个List<SubscriberMethod>。有多少onEvent函数,返回的List,就有多少个item。

即查找订阅源内的事件处理方法,同一时候还会查到它的父类中的事件处理方法。返回list,交给

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority)

 进行处理。
     Event与Subscriber之间,是一对多的关系。

即一个事件,能够被多个订阅者关注。

     Subscriber与Event之间,也是一对多的关系。

即一个订阅者,能够订阅多个事件。

     subscribe方法。也就是将上述的那样的关系。进行理顺,合理的建立map的映射关系,主要做了这样几件事件。
     a.依据SubscriberMethod中的EventType类型,将Subscribtion对象存放在subscriptionsByEventType中。建立EventType与Subscription的映射。一个事件能够有多个订阅者。
    b.依据Subscriber将EventType存放在typesBySubscriber`中,建立Subscriber到EventType的映射,每一个Subscriber能够订阅多个事件。
    c.假设是Sticky类型的订阅者,直接向它发送上个保存的事件(假设有的话)。
     通过Subscriber到EventType的映射,我们就能够非常方便地使一个Subscriber取消接收事件,通过EventType到Sucscribtion的映射,能够方便地将对应的事件发送到它的每个订阅者。

    与Observer不同的是。使用EventBus。不同的被观察者,不需统一实现Observer中的interface方法。在上层代码中,也不须要逐一进行notify机制。通过Map进行订阅源与事件函数的相应关系,进行解耦,为其核心之处。
       发送流程:
         EventBus.getDefault().post(new EventType());參数为用户自己定义的对象。最为简单的处理方式,实现事件发送。
     当事件发送出去后,全部的订阅者。是怎样调用其事件方法的呢?这个就须要遍历上文提到的subscriptionsByEventType的Map了。
Post发送事件,入口为post函数:public void post(Object event),在postSingleEvent函数中个,有一个重要的处理函数:

    /** Finds all Class objects including super classes and interfaces. */
    private List<Class<?>> findEventTypes(Class<?

> eventClass) { synchronized (eventTypesCache) { List<Class<?>> eventTypes = eventTypesCache.get(eventClass); if (eventTypes == null) { eventTypes = new ArrayList<Class<?

>>(); Class<?> clazz = eventClass; while (clazz != null) { eventTypes.add(clazz); addInterfaces(eventTypes, clazz.getInterfaces()); clazz = clazz.getSuperclass(); } eventTypesCache.put(eventClass, eventTypes); } return eventTypes; } }

         其作用。就是把这个事件类的对象、实现的接口及父类的类对象存到一个List中返回。依据list中的eventTypes,遍历subscriptionsByEventType,获取订阅源对象。进行逐一的调用事件函数。
        这里须要注意的是,当Post一个事件时,这个事件的父事件(事件类的父类事件)、接口事件也会被Post,所以假设订阅者接收Object类型的事件,即包括onEvent(Object object)事件函数。那么Subscriber就能够接收全部的事件。
          通过本篇博文的了解,EventBus就是通过Map。建立订阅源与事件函数的相应关系,进行解耦,来规避Observer的接口方法的多次、频繁的定义。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/116266.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Idea激活码永久有效Idea2020.1.3激活码教程-持续更新,一步到位

    Idea激活码永久有效Idea2020.1.3激活码教程-持续更新,一步到位Idea激活码永久有效2020.1.3激活码教程-Windows版永久激活-持续更新,Idea激活码2020.1.3成功激活

    2022年6月17日
    280
  • HTML入门与进阶以及HTML5

    HTML入门与进阶以及HTML5目录一、简介1、前端开发最核心技术(1)HTML是什么?(2)CSS(3)JavaScript2、前端开发其他技术二、基础内容1.基础总结2.HTML的基本标签(1)HTML标签(2)head标签(3)body标签3、段落与文字(一)、段落标签(二)、网页特殊符号(三)、自闭合标签(四)、块元素和行内元素(五)、练…

    2022年6月4日
    45
  • linux 修改mysql端口「建议收藏」

    linux 修改mysql端口「建议收藏」1)先关闭MySQL的进程2)更改端口vim/etc/my.cnf添加:port=33083)重启MySQL服务:servicemysqldrestart4)查看MySQL的端口号3.1.登录mysqlmysql-uroot-p3.2.查看当前端口号showglobalvariableslike‘port’;…

    2022年10月3日
    2
  • ActivityManager解析及使用

    ActivityManager解析及使用前言 Activity 可以获取运行中的应用信息 可以获取到 servcie process app memory 信息等 获取信息 ActivityMana MemoryInfoMe 中重要的字段 availMem 系统可用内存 totalMem 总内存 threshold 低内存阈值 即低内存的临界线 lowMemory 是否为低内存状态 Debug M

    2025年8月7日
    26
  • python怎么运行ipynb文件_jupyter如何打开D盘的文件

    python怎么运行ipynb文件_jupyter如何打开D盘的文件2019独角兽企业重金招聘Python工程师标准>>>…

    2022年8月26日
    9
  • python贪吃蛇游戏代码详解外加中文_Python贪吃蛇代码

    python贪吃蛇游戏代码详解外加中文_Python贪吃蛇代码感觉游戏审核新政实施后,国内手游市场略冷清,是不是各家的新游戏都在排队等审核。媒体们除了之前竞相追捧《PokemonGo》热闹了一把,似乎也听不到什么声音了。直到最近几天,突然听见好几人都提到同一个游戏,网上还有人表示朋友圈被它刷屏了。(不过现在微信已经悍然屏蔽了它的分享)这个游戏就是现在iOS免费榜排名第一的《贪吃蛇大作战》。一个简单到不行的游戏,也不知道怎么就火了。反正一款游戏火了,各路媒体…

    2022年8月10日
    23

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号