本文通过一个办公审批的应用案例,介绍如何使用BlackBerry UI API为用户在黑莓手机开发用户界面程序,如何使用UI组件(Screen,Manager,Field),如何扩展高级UI组件ListField,如何通过菜单/按钮/按键来响应用户交互,如何通过布局管理器Manager来处理特殊的UI布局和显示效果,最后通过OTA无线部署这个应用到用户的黑莓手机设备上。
面向对象:
对黑莓手机应用开发感兴趣,对黑莓应用开发稍有了解但是还没有实战经验,希望能对BlackBerry
UI开发有个更深入的了解。
目标:在本文的办公审批的应用案例中,企业客户要求开发一个运行在黑莓手机上面的用于办公申请和批准的应用程序,让移动办公的用户和他们的领导能及时地提交/查看/审批办公申请。
应用程序的主要用户窗口有两个:
1.等待审批的办公申请记录列表,用户可以通过菜单新建,保存,查看,删除申请记录;
2.查看每条申请记录的详情信息,领导可以查看,通过,或者拒绝该申请。
要点:
1.准备开发环境,创建新的BlackBerry项目,创建最简单的UI应用程序Hello World,在开发环境中内置的黑莓9700模拟器中运行。
2.创建主从共两个窗口(Screen);创建菜单为主从窗口进行之间进行导航。
3.为主窗口添加可以在列表中滚动显示数据的高级字段ListField,该字段和待审批的申请记录列表进行数据绑定。
4.为从窗口添加显示和输入字段(Field),命令按钮。使用布局管理器处理UI布局,背景色。
5.处理黑莓手机的返回键(Return),轨迹球(TrackBall)事件,输入字段数据变化等事件。
6.配置模拟器中文显示,单步跟踪调试。
7.OTA应用部署,为不同OS版本的手机8300/9700分别打包应用程序为jad/alx包,架设
OTA部署服务器,为8300/9700手机自动部署对应OS版本的程序。
8.后记。
对读者的前提要求:
要求读者对BlackBerry平台/BlackBerry UI API/Java语言都稍有了解。
1准备开发环境
准备开发环境,创建新的BlackBerry项目,创建最简单的UI应用程序HelloWorld,在开发环境中内置的黑莓9700模拟器中运行。
1.1准备开发环境,下载并安装BlackBerryJavaPlug-inforEclipse开发工具本文使用的BlackBerry Java Plug-in for Eclipse版本为:v1.1beta2(1.1.1),相对于JDE该工具简称e JDE。e JDE 1.1.1内置eclipse 3.5.1。e JDE 1.1.1内置BlackBerry Java SDK version 5.0.0。而BlackBerry Java SDK里面又包括MDS模拟器,手机模拟器simulator,例子代码samples,文档docs等内容。
(下载地址:http://na.blackberry.com/eng/developers/devbetasoftware/javaplugin.jsp)
1.2创建BlackBerry Project启动Eclipse,File New Other,选择BlackBerry Project,填写Projectname为UI Sample,选择JRE->Useaprojectspecific JRE为BlackBerry JRE 5.0.0,点击Finish按钮创建项目。
注:向导中的BlackBerry JRE 5.0.0对应BlackBerry Java SDK version 5.0.0,后者内置采用BlackBerry OS 5.0.0的黑莓9000/9550/9700手机模拟器。如果需要开发测试针对黑莓8310等其他型号手机的应用程序,你可以通过eclipse在线更新的方式安装4.2.1/4.5/4.6/4.7等版本的BlackBerry Java SDK,比如SDK version 4.5内置黑莓8310手机模拟器。具体如何通过eclipse在线升级请参考www.blackberry.com/developers网站。
1.3导入HelloWorld例子代码
把开发工具内置的例子代码hello world demo导入到项目src目录。BlackBerry开发工具带了几十个例子程序在:\TOOLS\BlackBerry_JDE_PluginFull_1.1.1\plugins\net.rim.ejde.componentpack5.0.0_5.0.0.14\components\samples目录下面。把com\rim\samples\device\helloworlddemo目录(包括com\rim\samples\device等父目录,Java代码和png图片)拷贝到项目src目录下面。
1.4为程序添加手机上面的图标
鼠标双击BlackBerry_App_Descriptor.xml文件,在第一个栏目(Application栏目)的右边Applicationicons区域点击Add按钮,选择src\com\rim\samples\device\helloworlddemo\image\helloworld_jde.png文件,保存。
1.5在开发工具内置的模拟器中测试HelloWorld应用
鼠标点击eclipse菜单Run->Run Configurations,在对话框中点击左上角的按钮,创建新的模拟器配置环境;修改Name为UI Sample;在对话框右边第一个栏目Projects栏目中勾上UI Sample项目;在对话框右边第三个栏目Simulator栏目中Device区域选择带qwert键盘的黑莓9700手机(缺省的模拟器是黑莓9550Storm2,这款手机不带qwert键盘,该型号模拟器不是特别方便在PC机屏幕上操作);点击Run命令按钮运行。
1.6在手机模拟器上运行Hello World
运行在手机模拟器Downloads文件夹中,你可以看到Hello World演示程序的图标,运行这个程序。运行结果如图。
2创建主从共两个窗口(Screen);创建菜单为主从窗口进行之间进行
导航
下面我们将创建主从共两个窗口(Screen),一个是初始的申请记录列表窗口,一个是申请记录详细内容。
3.为主窗口添加可以在列表中滚动显示数据的高级字段ListField,该字段和待审批的申请记录列表进行数据绑定。
最终的运行结果如图
你可以看到屏幕中间列表显示的三条待审批的记录,用户打算通过菜单对审批记录进行操作。
4为从窗口添加显示和输入字段;使用布局管理器处理UI布局,背景色
4.1从窗口用户界面的划分从程序设计的角度,从窗口被分割为两个重要的部分:申请编辑区域,按钮区域。另外还有标题区域,分割横线。
|-------------------------- |
| 标题 |
|-------------------------- |
| 多个输入 域 | < --------- 编辑区域 , displayMessa ge( ) 方法
|--------- 分割横线 - -- -------|
| 同意 返 回 | < --------- 按钮区域 , displayButto n() 方法
|-------------------------- |
4.2构造方法
编辑区域包括两个输入域Edit Field,一个可以多行录入的文本输入域Text Field,一个时间输入域DateField。按钮区域包括两个按钮,并排排列。
- public class MessageViewScreen extends MainScreen { MessagesListField _list;
- Message _message;
- boolean _editable;
- final static int MAX_CHARS = 128; EditField senderField;
- EditField subjectField; TextField contentField; DateField dateField;
- ButtonField newButton; ButtonField agreeButton; ButtonField returnButton;
- // 父窗口的 数据通 过参 数 list 和 message 传递 过来,并 且通过 editable 参 数告知 这个窗 口是用来 显示数 据,还 是 用来编辑 数据的 。
- public MessageViewScreen(MessagesListField list, Message message, boolean editable) {
- _list = list;
- _message = message;
- _editable = editable;
- displayMessage();
- add(new SeparatorField());
- displayButton();
4.3编辑区域coding
在display Message()方法中,以可修改或者只读的样式(style)在窗口中添加各种输入字段。在屏幕(Screen)上面添加输入字段(Field)是一件很容易的事情,只需要调用add(字段)方法就可以了。但是客户新要求设置所有输入字段的背景颜色为淡蓝色。一种常用的方法是使用VerticalFieldManager布局管理器类,在布局管理器中设置背景色,然后调用manager.add(field)把相应输入字段放进这个布局管理器里面。
- protected void displayMessage(){
- VerticalFieldManager manager;
- manager = (VerticalFieldManager)getMainManager();
- Background bg = BackgroundFactory.createSolidBackground(Color.LIGHTBLUE);
- manager.setBackground(bg);
- long style;
- style = EditField.READONLY;
- if (_editable) style = EditField.EDITABLE;
- senderField = new EditField(" 提交人 : ", _message .getSender(), MAX_CHARS, style);
- manager.add(senderField);
- // 其他类似 代码从 略
- 。。。
- dateField = new DateField(" 提交日期 : ", (new Da te()).getTime(),DateFormat.DATE_MEDIUM);
- manager.add(dateField);
- // 其他类似 代码从 略
- 。。。
- }
4.3命令按钮区域coding
在displayButton()方法中,添加两个命令按钮,这两个命令按钮按照布局管理器FooterManager的处理被横着摆放,中间有一定的间隔;两个命令按钮和事件处理类FieldChangeListener关联,以处理用户点击按钮的事件,进而审批通过或者是直接返回上级父窗口。
- protected void displayButton() {
- //------------------------------------------------------------------
- // 创建按钮 点击 事 件监听 类 FieldChangeListener
- FieldChangeListener myButtonListener = new FieldChangeListener() {
- public void fieldChanged(Field field, int context) { ButtonField fieldChanged = (ButtonField) field;
- //begin testing to see what field changed if( fieldChanged == newButton) {
- Message message = new Message(new Date(), sen derField.getText(),
- subjectField.getText(), contentField.getText(), Message.STATUS_NEW);
- _list.addMessage(message);
- close();
- }
- // 其他类似 代码从 略
- }
- };
- //-------------------------------------------------- ----------------
- FooterManager manager = new FooterManager();
- newnewButton = new ButtonField(" 提交 ");
- newButton.setChangeListener(myButtonListener);
- if (_editable) manager.add(newButton);
- // 其他类似 代码从 略
- // 最后把布 局管理 器连同 里面 的两个按 钮一起 放到 从 窗口上
- add(manager);
- }
4.4自定义布局管理器
BlackBerry UI API中,屏幕窗口的布局管理器有很多,比如Flow Field Manager,Grid Field Manager,Horizontal Field Manager,Vertical Field Manager以及延伸出来的各种子类。但是客户的要求多种多样,这些窗口管理器不一定能满足所有客户的要求。
在本案中,客户提出屏幕下方的两个命令按钮需要并排摆放,这看上去是可以用Horizontal Field Manager来处理,但是客户又指定说这两个命令按钮摆放的时候,第一个按钮距离屏幕左边两个字符大小,第二个按钮距离屏幕中间左边两个字符大小。这就需要我们自己编写一个窗口管理器,在sublayout(intwidth,intheight)方法中通过set Position Child()方法设置各个按钮Field的摆放位置,通过layout Child()方法设置Field的高度/宽度;通过set Extent(intwidth,intheight)方法设置这个区域的高度和宽度。
- p ublic class FooterManager extends Manager {
- public FooterManager() {
- super(0);
- }
- protected void sublayout (int width, int height) {
- int fieldWidth = 100;
- int filedHeight = 100; Field field = getField(0);
- // 设置 filed 的 x 位 置为从 左边起 ,空两个 字符; y 位置为 0
- setPositionChild(field, getFont().getHeight() * 2, 0);
- layoutChild(field, fieldWidth, filedHeight); //lay out the field
- field = getField(1);
- // 设置 filed 的 x 位 置为从 中间 左边起, 空两个 字符; y 位置为 0
- setPositionChild(field, width/2 + getFont().getHei ght() * 2, 0);
- layoutChild(field, fieldWidth, filedHeight); //lay out the field
- // 设置整个 区域的 高度为 按钮 字段的高 度即可 ,不需 要很高
- setExtent(width, getFont().getHeight() + 20);
- }
4.5从窗口的最终运行结果如图
5处理黑莓手机的返回键(Return),轨迹球(TrackBall)事件,输入字段数据变化等事件
5.1键盘/轨迹球事件处理
在主窗口MessagesListViewScreen中,每当用户按下黑莓的滚轮,或者轨迹球,或者是按下键盘上面的回车键,用户都希望能打开并查看他所选中的申请记录。
- protected boolean navigationClick (int status, int time) { Message message = list.getSelectedMessage();
- //Open message screen
- MessageViewScreen screen = new MessageViewScreen(list, message, false); UiApplication.getUiApplication().pushScreen(screen);
- return true;
- }
- protected boolean keyChar (char key, int status, int time) {
- boolean retVal = false;
- if(key == Characters.ENTER){
- Message message = list.getSelectedMessage();
- //Open message screen
- MessageViewScreen screen = new MessageViewScreen(list, message, false);
- UiApplication.getUiApplication().pushScreen(screen);
- retVal = true;
- }
- return retVal;
- }
5.2输入字段数据变化事件处理
在从窗口Message View Screen,如果是新建申请记录,当用户在屏幕中录入或者修改了数据,然后按qwert键盘上的Return键试图关闭当前窗口的时候,我们可以在onSave()方法中捕获用户的退出事件,把用户的输入保存起来。
这里我们把新建记录保存到主窗口的申请记录列表_list里面。
- protected boolean onSave() {
- boolean save = super.onSave();
- if (save) {
- Message message = new Message(new Date(dateField.getDate()),
- senderField.getText(), subjectField.getText(), contentField.getText(), Message.STATUS_NEW);
- _list.addMessage(message);
- }
- return save;
- }
6配置模拟器中文显示,单步跟踪调试
6.1配置模拟器使之具备显示中文,录入中文的能力大部分开发工具(JDE/e JDE)内置的或者是独立安装的手机模拟器缺省都没有安装中文语言包,缺省用户界面是英文。我们可以编辑相应的模拟器配置xml文件,加入中文语言包和输入法,然后在模拟器里面点击Options->Languageand Text Input->Language,选择“简体中文”,在模拟器里面点击Options-->Languageand Text Input->Input Language,选择“拼音(简体中文)”,保存即可;如果在测试模拟器配置xml文件之前运行过这个模拟器,那么需要执行components\simulator\clean.bat脚本把模拟器环境清理为干净的运行环境,这一过程大概需要2到3分钟。
ComponentPack5.0/OS5.0/9700模拟器的配置:
编辑eJDE安装目录plugins\net.rim.ejde.componentpack5.0.0_5.0.0.14\components\simulator\9700.xml文件,在之前加入下面四行,就可以让9700模拟器具备显示中文的能力。
ComponentPack4.5/OS4.5/8300模拟器的配置:
- < App lic at ion > n e t.rim .b lackb e rry .lan g.zh _ CN< /App lic at ion >
- < App lic at ion > n e t.rim .b lackb e rry .lan g.zh _ CN.de f au ltRe s ou rce< / App lic at ion >
- < App lic at ion > n e t.rim .b lackb e rry .lan g.zh _ CN.lo caliza tio n < / App lic at ion >
- < App lic at ion > n e t.rim .b lackb e rry .lan g.zh _ CN.re nde rin g< /A pp lic at ion >
编辑eJDE安装目录plugins\net.rim.ejde.componentpack4.5.04.5.0.21\components\simulator\8300.xml文件,在之前加入下面两行就可以让9700模拟器具备显示中文和输入中文的能力。
- < App lic at ion > n e t.rim .b lackb e rry .lan g.zh _ CN_P iny in < /App l ication >
- < App lic at ion > n e t.rim .b lackb e rry .lan g.zh _ CN.re nde rin gSup p ort
6.2单步跟踪调试
在BlackBerry开发环境中对手机程序进行单步跟踪调试是一件很容易的事情。BlackBerry Java Plug-in for Eclipse可以借助eclipse强大的debug能力对手机程序进行代码跟踪调试。具体操作很简单,只要在代码编辑界面中,双击左边边框加入跟踪断点,然后点击eclipse按钮Debug即可。
在debug过程中,eclipse的debug功能大都能够使用,包括单步跟踪调试,显示和编辑代码中的变量等等。这里就不赘述了。
提示:手机程序Java代码System.out.println的输出只有在eJDEdebug状态中才会输出到eclipse console窗口上。
7OTA应用部署
应客户的要求,需要为不同OS版本的手机8300/9700分别打包应用程序为jad/alx包,并架设
OTA部署服务器为8300/9700手机自动部署对应OS版本的程序。
7.1为不同OS版本的手机8310/8910分别打包应用程序为jad/alx包在开发工具中,为不同OS版本的手机,比如OS4.5的8300,OS5.0的9700手机分别打包是一件轻而易举的事情。首先在eclipse选择项目,选择菜单Project->Properties,左边选择JavaBuildPath,右边横向栏目选择第三个Libraries,你可以看到项目当前配置的Build环境设置为哪个版本OS版本。选择“JRESystemLibrary[BlackBerryJRE5.0.0]”,选择“Edit”按钮,在对话框AlternateJRE选择BlackBerryJRE4.5.0,然后保存。
接下来选择菜单Project->BlackBerry->PackageProject(s),很快你就可以在项目的deliverables目录下面看到4.5.0子目录,里面是刚刚package好的cod二进制运行文件,jad等文件。现在你可以OTA方式无线部署这个应用到手机上面了,或者是使用javaloader命令行安装cod文件到手机上。
如果你想让用户可以在电脑上面通过黑莓桌面管理器安装软件给手机,那么你只需要编辑
BlackBerry_App_Descriptor.xml文件,在第二个栏目Build里面,勾上Generate.alxfile选项,然后重新package项目即可生成alx文件。
7.2架设OTA部署服务器为8300/9700手机分发程序
在开发人员教程-RIM开发人员教程“A70如何部署和分发应用程序”中对如何设置OTA服务器有详细的描述。这里就简单说明一下。
首先安装apachehttpserver2.0,编辑conf/mime.types文件,在最后加入下面三行,然后重新启动apache服务器。
- app lic at ion /ja v a - arch i v e jar app lic at ion /v nd .rim .cod cod text/v nd .s un .j2 me .ap p - d es cri p to r jad
然后把BlackBerry项目deliverables目录下面的4.5.0和5.0.0两个子目录连同文件拷贝到apachehtdocs目录下面,在htdocs目录下面创建一个包含指向两个不同jad文件的链接的html文件。现在,用户可以用黑莓8300或者9700手机(或者是手机模拟器通过MDS模拟器)访问该html,进而选择不同的jad文件链接以OTA方式无线下载安装应用了。
7.3架设OTA部署服务器为8300/9700手机自动部署对应OS版本的程序
上一节中,通过apacheweb服务器html页面发布手机程序,需要最终用户在手机浏览器页面上手工选择手机型号/操作系统版本,然后点击安装,这对企业用户而言用户体验并不友好。我们希望当企业用户使用8300手机访问http://192.168.1.102:8080/UISample.jad的时候,服务器可以自动地把对应的4.5.0/UISample.jad,4.5.0/UISample.cod等文件分发给手机;而当企业用户使用9700手机访问http://192.168.1.102:8080/UISample.jad,服务器可以自动地把对应的5.0.0/UISample.jad,5.0.0/UISample.cod等文件分发给手机。
幸运的是,黑莓手机会把自己的设备型号/操作系统版本等信息通过http请求头传递给Web服务器。比如8300手机传递给服务器的httpheaderuser-agent的值为BlackBerry8300/4.5.0.44Profile/MIDP-2.0Configuration/CLDC-1.1VendorID/-1;9700手机传递给服务器的httpheaderuser-agent的值为BlackBerry9700/5.0.0.334Profile/MIDP-2.1Configuration/CLDC-1.1VendorID/-1。有了user-agent信息,Web服务器就可以了解客户端设备的能力。
在Tomcat等J2EE服务器上面,你可以通过ServletAPIrequest.getHeader("user-agent")获得上述信息,然后自动找到对应版本的jad/jar/cod文件发送给客户端。服务器端编码的工作,前人已经做了很多,我们拿来稍微改就可以在J2EE服务器上面自动地为不同型号黑莓手机分发对应版本的应用程序文件了。
我们为黑莓手机对Sun网站提供的代码做了如下修改。
首先修改provisioner.props文件,设定8300和9700对应的不同目录下面的UISample文件。(相应的,要把BlackBerry项目deliverables目录的两个子目录4.5.0和5.0.0和里面的文件拷贝到J2EE WAR文件根目录下面)。
- device[BlackBerry8300]=BlackBerry8300
- device[BlackBerry9700]=BlackBerry9700
- BlackBerry8300[UISample.jad]=4.5.0/UISample.jad
- BlackBerry8300[UISample.jar]=4.5.0/UISample .jar
- BlackBerry8300[UISample.cod]=4.5.0/UISample.cod
- BlackBerry9700[UISample.jad]=5.0.0/UISample.jad BlackBerry9700[UISample.jar]=5.0.0/UISample.jar BlackBerry9700[UISample.cod]=5.0.0/UISample.cod
然后修改Provisioner.java代码,加入cod文件后缀的MIME定义(原有代码已经有jad和jar的MIME定义)。
- // The Bl ackBerr y COD e xte nsio n
- priv at e s t ati c fi na l St ri ng COD_ E XT = " .co d";
- // The Bl ackBer r y COD M IME ty pe - J i an g
- private s tatic final S tring COD_MIME = " a pplicat i on/vnd.ri m.c od";
在streamFile(file,response)方法中加入对CODMIME类型的处理,告诉客户端浏览器将要发送cod文件以及对应MIME类型。
- i f ( f ile .g et P at h() .e nd sWit h( J AD_ E XT ) ) re spo nse .s et Co nte nt T y pe ( J AD_M I M E ) ;
- i f ( f ile .g et P at h() .e nd sWit h( J AR_ E XT ) ) re spo nse .se t Co nte nt T y pe ( J AR_M IME ) ;
- i f ( f ile. g et Pa t h ().endsWith( COD_ EXT )) response. s etContent T yp e ( COD_MIME );
在doGet()方法的最前面通知手机浏览器和代理服务器(比如BlackBerryMDS)对此URL不要做任何cache处理。
- re spo nse .se t He ader( "C ac he -C o ntrol ", "no - st ore "); //H T T P 1.1
- re spo nse .se t He ader( "P r agm a" ,"no -c ac he "); //HT T P 1. 0
- re spo nse .se t Date He ade r ( "E xpire s", 0); //preve nt s c ac hi ng a t t he p ro xy s erve r
现在我们把 这个 J 2E E WAR 包部署到 T om cat 服务器上 面,不同 手机通 过一个 U RL 就可以安 装对应 的不同版 本的手 机程序 了, 这大大提 高了用 户体验 ,降 低了管理 员维护 的负担 。
现在我们把这个J2EEWAR包部署到Tomcat服务器上面,不同手机通过一个URL就可以安装对应的不同版本的手机程序了,这大大提高了用户体验,降低了管理员维护的负担。
8后记
经过以上整个开发部署流程,从环境搭建,代码开发,模拟器测试,单步跟踪调试,中文模拟器配置,到静态和动态自动的OTA部署,我们可以把这个典型的移动办公审批场景下的应用程序部署到客户手机终端上了。
相信读者看完本文以后有信心自己动手在黑莓手机平台上面开发移动办公应用了。您回到公司后,可以从调研企业领导和业务人员需要及时有效处理的业务流程着手,马上开始调研/设计/开发企业的移动办公应用。
注:在黑莓手机平台上,可以采用BlackBerryUIAPI(net.rim.device.api.ui包)/MIDPUIAPI(javax.microedition.lcdui包)/Widget(HTML,CSS,以及JavaScript)等三种API开发应用程序的用户界面,其中前面两种是Java API,Widget是WebUIAPI。