本来不想写J2ME开发的时候要根据不同手机平台适配各种键值这个问题,觉得没撒意思,也没什么技术含量,但是今天看到了一个让我很无语的东西,所以我决定要写出来。稍候再说这个让我不爽的东西,先不要影响我们分享技术的心情。NOW BEGIN …
故事背景:最近要开发一个世界天气在线搜索的软件,先AD一下,这个软件是我们Allove Team开发的有一个生活小软件,开始的定位就是天气搜索,后来我想扩展为“生活小助手”就是不但有世界天气搜索,还有出行参考,还有生活常识之类的东西。正在开发中。 由于,开发过程中需要使用Canvas才能做出很漂亮的界面,所以引发了一个老问题 — 手机键值!
很多人都说,要适配所有手机的键值是不可能的。因为,已是J2ME中没有对手机的左右软键的键值定义,而是很多手机也没定义,再者就是手机多多了,像华为,中兴,联想,诺基亚,摩托罗拉,西门子,索爱,黑莓,多普达等等这些大厂家都没个定数,更别所多如牛毛的山寨机了,所以这种说法也是无可厚非的。 即使你把 左键 -7 , 右键 -6 , OK键 -5 这些都设置好能支持大部分的手机,还是难免有个害群之马啊。 所以, 没有标准导致了这个严重的问题 :要一次性搞定所有手机的键值问题难道非常之大。
但是,天知道我怎么一生下来就是个不信邪的主儿,Google百度了几下发现没有统一键值之后开始思考自己的路了。最后,想了一个办法,目的是我要一次性搞定所有手机的键值。怎么做?让用户手机告诉你呗。思路如下:用户第一次使用时设置键位。
- 用Canvas实现一个键位设置界面,捕获keyPressed事件;
- 在设置界面中以提示性语言引导用户按键;
- 将得到的键值保存到RMS中备用;
- 完成键位设置;
- 在以后要使用按键的Canvas中调用RMS中的数据,完成操作。
下面是完成这个设置的简要代码结构:
- //首先你需要一个数组:
- private String[] drawArray = {"左功能键","右功能键","OK键","方向键【上】","方向键【下】","方向键【左】","方向键【右】"} ;
- //然后你需要两个标志位
- private boolean config_finished = false ;
- private boolean firsttime = true ;
- //再者你需要一点实现逻辑
- if(drawIndex > 6){
- config_finished = true ;
- }
- if(!config_finished){
- if(firsttime){
- g.drawString("【键位设置】",WIDTH / 2 - titleWidht / 2 , startY, Graphics.TOP|Graphics.LEFT);
- g.drawString(initStr, 5, startY + 1*lineHeight, Graphics.TOP|Graphics.LEFT);
- g.drawString(prefix + drawArray[drawIndex] , 5, startY + 2*lineHeight, Graphics.TOP|Graphics.LEFT);
- } else {
- g.drawString("【键位设置】",WIDTH / 2 - titleWidht / 2 , startY, Graphics.TOP|Graphics.LEFT);
- g.drawString(initStr, 5, startY + 1*lineHeight, Graphics.TOP|Graphics.LEFT);
- g.drawString(finished + drawArray[drawIndex - 1] + status, 5, startY + 1*lineHeight, Graphics.TOP|Graphics.LEFT);
- g.drawString(prefix + drawArray[drawIndex] , 5, startY + 2*lineHeight, Graphics.TOP|Graphics.LEFT);
- }
- firsttime = false ;
- startY = 0 ;
- initStr = "" ;
- } else {
- System.out.println("设置完毕 .... config finished ...");
- g.setColor(0xff0000);
- g.drawString("设置成功,请按OK键返回!", 5, startY + 4*lineHeight, Graphics.TOP|Graphics.LEFT);
- }
- //接下来我们需要一点控制信心和按键事件的响应
- protected void keyPressed(int key){
- if(this.storeKeyValue(WHAT_KEY, key)){
- drawIndex ++ ;
- WHAT_KEY ++ ;
- status = "(成功)" ;
- } else {
- drawIndex -- ;
- WHAT_KEY -- ;
- prefix = "[重设]" ;
- status = "(失败)" ;
- }
- if(config_finished && key == config.getOK()){
- System.out.println("read back of OK .. is " + config.getOK());
- wm.setThisAsCurrent(wm.getMainform());
- }
- repaint();
- }
- //最后我们需要一个存储的动作
- private boolean storeKeyValue(int whatkey , int key){}
请注意,上面这个代码片段只是完成按钮设置的框架,而不是完整代码,如果你需要完整代码可以留下信息并且发邮件告诉我。我会分享给你的。
下面说一下上面这段代码的大致思路:
创建一个你希望设置的键位的数组:private String[] drawArray , 里面存放着一些提示信息,这些信息用来引导用户去按键,然后使用paint()在界面上绘制这些信息,但又按键事件的时候系统会调用protected void keyPressed(int key)方法,而我们在这个方法中处理一些事件,不作一些控制。例如改变绘制字符串的指针,例如修改键位设置的执行状态 “成功” 或者 “失败” 。 另外还需要控制的就是设置的完成状态 , 最终目的是把键值写入到RMS中备用 。
下面是键值调用的持久类的完整代码:
- package org.allove.weather.lib;
- public class KeyMap {
- ///////////////
- private static KeyValueRms config = KeyValueRms.getInstance();
- public static final int key_LeftSoft = config.getLeftSoft() ;
- public static final int key_RightSoft = config.getRightSoft() ;
- public static final int key_OK = config.getOK() ;
- public static final int key_UP = config.getUP() ;
- public static final int key_DOWN = config.getDown() ;
- public static final int key_LEFT = config.getLeft() ;
- public static final int key_RIGHT = config.getRight() ;
- ///////////////
- }
至于这个KeyValueRms 怎么去实现就不是本文的主要内容了,这是RecordStore的内容,这里就不赘述了 。
总的来说,我觉得这是一个很简单的问题,也很容易想到,应该不到5分钟吧,想到这个解决方案。由于我觉得这个东西很简单,价值也不那么明显,所以导致了我看到一个东西之后很郁闷。今天,无意中搜索键值玩,发现了万方数据里面的一片论文:《一种J2ME软件适配不同手机键值的方法》让我倍感无语。这个方法被人申请专利了,我很无语,这东西也能申请壮丽,我操,早知道我早两年也去申请了。 还说得那么玄乎,很纠结啊。
最后,要来说一下这个可行性和用户体验的问题。
- 其实这东西不是很好,完全依赖于keyPressed方法,如果不支持这个方法呢?
- 在某些手机中按左右软键的时候是没有反应的,比如巨头诺基亚
- 再说用户体验,这个问题有点严重,一旦设置错误可能就需要从新安装软件,这是相当不友好的,因为RMS的数据要卸载才能清除,其实这个到也无所谓啦,你可以在软件里面做一个重新设置的功能,这到不致命
- 然后就是,不是所有用户都能看懂你的引导语言,难免会设置错误,你不能保证每个用户都是聪明的
- 由于手机厂商数目巨大,这个方法的代价是巨大的,慎用
抛弃这种方法之后如何去更快捷的适配不同手机的键值问题呢?也许按手机型号发布软件是一个最简单最直接的方案,局限性就是你必须知道每个平台的键值,希望MIDP3.0不要再有这个问题了。现在,我们就假设,我们已经能够获取到不同手机的键值,那么我们应该如何去写代码呢?在每一个 keyPressed里面设置switch case -6 / -7 / -5 的方法显然是不对的。 我们希望这样操作:
- package org.allove.weather.lib;
- public class KeyMap {
- ///////////////
- public static final int key_LeftSoft = -7 ;
- public static final int key_RightSoft = -6 ;
- public static final int key_OK = -5 ;
- public static final int key_UP = -4 ;
- public static final int key_DOWN = -3 ;
- public static final int key_LEFT = -2 ;
- public static final int key_RIGHT = -1 ;
- /////////////// 请注意 上面的键值只是为了测试 不一定正确
- }
- /////////////////////////////////////////
- // ..... Many Other Things ...
- import package org.allove.weather.lib.KeyMap ;
- public class ACanvas extends Canvas ;
- // ..... Many Other Things ...
- protected void keyPressed(int key){
- if(key == KeyMap.key_LeftSoft){
- do(.....) ;
- } else if (key == KeyMap.key_OK){
- do(.....) ;
- } else if (key == KeyMap.key_RightSoft){
- do(......) ;
- }
- repaint();
- }
- // ..... Many Other Things ...
相信这样的代码结构是可读的,方便维护的,容易移植的 。 当你需要移植平台的时候只需要在KeyMap中修改映射即可。这也许就是OO思想的体现吧 。 好了今天就到这里吧 , 上面的代码基本都是框架,如果你希望得到源码的话可以留言并且发邮件到sunjianyes#gmail.com获取,如果你能记得我们Allove Team那就最好不过了。再如果你能够支持一下我们的发展就更好了,最好的办法就是尝试使用我们的软件: m.Allove.org
如果你在下次看到下面这张图片的时候能想起我们那就是我们最大的成功: