PlayBook上的应用为用户呈现的是一个窗口系统。虽然平板电脑上的窗口系统和PC上的窗口系统有一些差别,但是其本质是完全相同的:应用程序再设备上展现一个图形窗口,然后等待用户动作,当用户动作发生时窗口会相应地作出响应。
在这样一个窗口系统中,事件的处理是其中的关键,程序启动后进入一个事件循环,等待用户事件的发生,当用户事件发生时调用对应的处理函数,完成对用户事件的响应。
在很多窗口系统中,事件循环是内置的,应用开发人员并不参与事件侦听,事件分发等动作,应用开发人员只是简单地定义动作相应的处理函数。比如,开发人员定义了一个按钮的“onClick()”方法,开发人员只需要实现“onClick”内部的代码,就是按钮被点击后该执行的动作。在这种系统中开发人员不用关心如何获取点击事件,如何判断点击的是不是该按钮。
在PlayBook NDK的窗口环境中是没有内置的事件循环的,应用开发人员需要自己实现事件循环。这一方面给开发人员带来了更多的工作量,在另一方面也很大提高了应用开发人员对应用的把控程度。
实现事件循环的基本方法就是程序完成了初始化工作后进入一个无限循环,每次循环都查看是否有事件发生,如果有事件发生获取该事件的信息,根据事件信息调用对应的处理函数,处理完了以后继续循环。
事件循环一般使用while做无限循环,不过,为了演示目的,下面的例子使用了for循环,处理了100个事件后就退出。
#include <stdio.h>
#include <assert.h>
#include <bps/bps.h>
#include <bps/event.h>
#include <bps/navigator.h>
int main(int argc, char *argv[]) {
fprintf(stderr, "Hello World!\n");
bps_initialize();
navigator_request_events(0);
int i = 0;
for (i = 0; i < 100; i++) {
int rc, domain;
bps_event_t *event = NULL;
fprintf(stderr, "Trying to get an event!\n");
rc = bps_get_event(&event, -1);
assert(rc == BPS_SUCCESS);
if (event) {
domain = bps_event_get_domain(event);
if (domain == navigator_get_domain()) {
fprintf(stderr, "Got a navigator event!\n");
}
}
}
return 0;
}
上面的代码是从HelloWorldConsole演变过来的,程序启动后在控制台输出“Hello World!”字样,然后完成一些初始化工作,接着进入事件循环,在循环中检查事件,或者事件,并执行相应动作。
该程序的初始化工作包括BPS初始化和事件注册两部分
BPS初始化通过代码bps_initialize()完成,BPS是BlackBerry Platform Service的缩写,BPS提供了PlayBook上的事件处理基础,包括在队列中保存事件,提供事件获取接口等。
有关BPS的更多内容在其它博文上再做介绍。
事件注册通过代码navigator_request_events(0)完成,该代码向BPS声明本应用需要获取“Navigator”事件。
初始化工作完成后进入一个for循环,循环开始部分通过bps_get_event(&event, -1)获取事件。
函数bps_get_event需要两个参数,第一个是bps_event_t的指针,用来保存所获取的事件,第二个是获取事件的方式,取值为负数,零,或者是一个正整数。如果第二个参数为负数则表示bps_get_event方法会一直等待到获取到一个事件为止。如果第二个参数是零则表示bps_get_event不会等待,有事件就获取,没有事件就继续执行后面的代码。如果第二个参数是一个正整数则表示等待指定的时间,期间获取到事件就返回,没有获取到事件就在指定的时间结束后返回。
上面样例使用的代码是bps_get_event(&event, -1),表示该方法会一直等待,直到获取到一个事件为止。
获取事件后的处理在本程序样例中比较简单,就是判断一下事件或许是否成功,所获取的事件是否为“Navigator”事件,是的话在控制台输出“Got a navigator event!”字样。
通过以上的样例大家可以对PlayBook NDK上的事件循环有一个初步的认识。不过,要写好一个事件循环并不是这么简单的,还需要考虑固定时间内获取多少次事件,事件处理异常等因素。我们在后面有机会继续讨论。