J2ME開發之手機鍵值適配
J2ME開發之手機鍵值適配
本來不想寫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軟件適配不同手機鍵值的方法》讓我倍感無語。這個方法被人申請專利了,我很無語,這東西也能申請壯麗,我操,早知道我早兩年也去申請了。FUCK! 還說得那么玄乎,很糾結啊。
最后,要來說一下這個可行性和用戶體驗的問題。
- 其實這東西不是很好,完全依賴于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
如果你在下次看到下面這張圖片的時候能想起我們那就是我們最大的成功: