Android 4.0日历(calendar)源码分析之CalendarController(事件分发)

 

                                                             2013.3.19  成都   晴  pm2.5  159  心情一般

日历在主体上只有一个AllInOneActivity.java,然后分别是各种Fragment。这就需要一个中介来统一处理他们的关系,AllInOneActivity和Fragment之间,以及不同的Fragment之间的通信(主要是事件),都是通过CalendarController这个类来完成的。

当在某个Fragment中想要发出一个事件的时候,该Fragment会用到自己实例化的CalendarController对象(mController),例如下面的样子:

mController.sendEvent(mContext, EventType.GO_TO, day, day, -1,
  
        mIsMiniMonth ? ViewType.CURRENT : ViewType.DETAIL,
  
        CalendarController.EXTRA_GOTO_DATE
  
                | CalendarController.EXTRA_GOTO_BACK_TO_PREVIOUS, null, null);

这里的sendEvent函数有很多参数,但是他们最终都会调用  CalendarController中重载了的public void sendEvent(Object sender, final EventInfo event),而之前的那些零散的参数都被封装在了这两个参数里。

sendEvent函数最终是要把EventInfo(事件信息)传递给事件处理对象(eventHandler),一个事件的处理对象可能还不止一个,因此需要遍历一次所有存在的事件处理对象,并调用这些对象的handleEvent(event)函数。

for (Iterator<Entry<Integer, EventHandler>> handlers =
  
        eventHandlers.entrySet().iterator(); handlers.hasNext();) {
  
    Entry<Integer, EventHandler> entry = handlers.next();
  
    int key = entry.getKey();
  
    if (mFirstEventHandler != null && key == mFirstEventHandler.first) {
  
        // If this was the 'first' handler it was already handled
  
        continue;
  
    }
  
    EventHandler eventHandler = entry.getValue();
  
    if (eventHandler != null
  
            && (eventHandler.getSupportedEventTypes() & event.eventType) != 0) {
  
        if (mToBeRemovedEventHandlers.contains(key)) {
  
            continue;
  
        }
  
        eventHandler.handleEvent(event);
  
        handled = true;
  
    }
  
}

那么事件处理对象,究竟是什么东西呢,其实他们非常平常,基本上,那些能通过自己的CalendarController成员变量mController发送事件的类本身也是事件处理对象,也就是我们熟悉的AllInOneActivity、MonthByWeekFragment、AgendaFragment、DayFragment。

这些类都继承了EventHandler这个接口(也就是事件处理对象的原型),并实现了其中的void handleEvent(EventInfo event);方法。EventHandler这个接口是在CalendarController中定义的,如下:

public interface EventHandler {
  
    long getSupportedEventTypes();
  
    void handleEvent(EventInfo event);
  
  
  
    /**
  
     * This notifies the handler that the database has changed and it should
  
     * update its view.
  
     */
  
    void eventsChanged();
  
}

刚才提到了遍历事件处理对象,也给出了遍历的那段代码,可以看到其实实在遍历这个集合eventHandlers,eventHandlers中的成员是通过public void registerEventHandler(int key, EventHandler eventHandler)方法得到的。

    public void registerEventHandler(int key, EventHandler eventHandler) {
  
        synchronized (this) {
  
            if (mDispatchInProgressCounter > 0) {
  
                mToBeAddedEventHandlers.put(key, eventHandler);
  
            } else {
  
                eventHandlers.put(key, eventHandler);
  
            }
  
        }
  
}

在mDispatchInProgressCounter > 0)(正在处理中的事件个数)的条件下,这时候只能将注册的新EventHandler放在mToBeAddedEventHandlers里,表示当前还不能立即处理,因为上次的还没处理完,如果mDispatchInProgressCounter<0则放在普通的eventHandlers里面,当sendEvent发生的时候,马上调用这些eventHandlers的handleevent方法。

mDispatchInProgressCounter正在处理的事件个数,是在sendEvent方法中被synchronized包括起来的程序段中赋值的。

在整个项目中搜素registerEventHandler(我不会告诉你我用的是SourceInsight工具)发现调用了次方法的地方如下:

AllInOneActivity中对四个视图的fragment进行了注册,当然并不是同时,假如当前是月视图,注册的当然是MonthByWeekFragment,要想了解如何注册的请看AllInOneActivity的setMainPane方法。或者参考我讲解AllInOneActivity的那篇文章。

其实,我们应该注意到,registerEventHandler只是对Fragment进行了注册(还有一些非AllInOneActivity的activity这里不讲解),但是事件处理对象中还有重要的AllInOneActivity,AllInOneActivity也有handleEvent的能力,AllInOneActivity为什么没有自己给自己注册一下呢,既然没有注册那么AllInOneActivity中的handleEvent方法不是永远不会被调用么?

当然不是AllInOneActivity也给自己注册了的,只不过是调用CalendarController的registerFirstEventHandler方法,方法定义如下:

    public void registerFirstEventHandler(int key, EventHandler eventHandler) {
  
        synchronized (this) {
  
            registerEventHandler(key, eventHandler);
  
            if (mDispatchInProgressCounter > 0) {
  
                mToBeAddedFirstEventHandler = new Pair<Integer, EventHandler>(key, eventHandler);
  
            } else {
  
                mFirstEventHandler = new Pair<Integer, EventHandler>(key, eventHandler);
  
            }
  
        }
  
}

之所以要区分于其他,是因为整个日历的架构中要求优先调用AllInOneActivity的handleEvent。假如mFirstEventHandler不为空,则最先处理他,registerFirstEventHandler也在方法之类调用了registerEventHandler,这样AllInOneActivity就有优先和普通两种身份。

  • 不管是registerFirstEventHandler还是registerEventHandler都有一个key参数,key是标识是不是同一个handler的键。

通过sendEvent发来的事件请求不一定都需要相应的handler来处理,如以下情况:

handler != null && (handler.getSupportedEventTypes() & event.eventType) != 0

Handler不存在的情况

事件类型不在支持的类型中

第一种情况好像还没遇到过,第二种情况的意思是,当我告知某个handler需要处理一个事件时,先判断这个handler自身是否支持该事件的处理,通过调用handler的getSupportedEventTypes方法就可以得到他所支持的事件类型。这里我们以AllInOneActivity为例:

getSupportedEventTypes本来是CalendarController的接口EventHandler的一个抽象方法,因为AllInOneActivity继承了该接口,因此AllInOneActivity重写了该方法,AllInOneActivity的实现如下:

    public long getSupportedEventTypes() {
  
        return EventType.GO_TO | EventType.VIEW_EVENT | EventType.UPDATE_TITLE;
  
}

可以看到AllInOneActivity能处理的事件也只有三种,跳转、查看日程、更新日历title上的日期。对于其他的handler,能处理的可能更少。

我们来看看其他的handler支持哪些事件。可能还没有找出所有的handler。

MonthByWeekFragment**:**

    public long getSupportedEventTypes() {

        return EventType.GO_TO | EventType.EVENTS_CHANGED;

}

DayFragment                       

    public long getSupportedEventTypes() {

        return EventType.GO_TO | EventType.EVENTS_CHANGED;

}

AgendaFragment

    public long getSupportedEventTypes() {

        return EventType.GO_TO | EventType.EVENTS_CHANGED | ((mUsedForSearch)?EventType.SEARCH:0);

}

SearchActivity

    public long getSupportedEventTypes() {

        return EventType.VIEW_EVENT | EventType.DELETE_EVENT;

    }

……………………此处略去若干字…………….

(getSupportedEventTypes()方法之后紧跟着handleEvent方法,这里就不一一列出handleEvent的具体实现了)

当没有hanlder来处理这些不支持的事件的时候,sendEvent会继续执行下面的代码,这些特殊的事件往往都和视图没有什么区别,在任何视图打开都是相同的结果,比如打开设置界面,打开搜索界面,打开选择要显示的日历界面等。代码如下:

if (event.eventType == EventType.LAUNCH_SETTINGS) {
  
      launchSettings();
  
      return;
  
  }
  
  
  
  // Launch Calendar Visible Selector
  
  if (event.eventType == EventType.LAUNCH_SELECT_VISIBLE_CALENDARS) {
  
      launchSelectVisibleCalendars();
  
      return;
  
  }

他会直接调用相应的函数,而不是交给handler处理。

Handler的这种处理机制运用了java中典型的回调机制,和观察者模式。