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

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

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

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

1
2
3
4
5
6
7
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(Objectsender, final EventInfo event),而之前的那些零散的参数都被封装在了这两个参数里。

 

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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这个接口(也就是事件处理对象的原型),并实现了其中的voidhandleEvent(EventInfo event);方法。EventHandler这个接口是在CalendarController中定义的,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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)方法得到的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    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工具)发现调用了次方法的地方如下:

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

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

 

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

 

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    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的实现如下:

1
2
3
4
5
    public long getSupportedEventTypes() {
   
        returnEventType.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会继续执行下面的代码,这些特殊的事件往往都和视图没有什么区别,在任何视图打开都是相同的结果,比如打开设置界面,打开搜索界面,打开选择要显示的日历界面等。代码如下:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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中典型的回调机制,和观察者模式。