1. 程式人生 > >(轉) J2ME開發之手機鍵值適配

(轉) J2ME開發之手機鍵值適配

本來不想寫J2ME開發的時候要根據不同手機平臺適配各種鍵值這個問題,覺得沒撒意思,也沒什麼技術含量,但是今天看到了一個讓我很無語的東西,所以我決定要寫出來。稍候再說這個讓我不爽的東西,先不要影響我們分享技術的心情。NOW BEGIN …

故事背景:最近要開發一個世界天氣線上搜尋的軟體,先AD一下,這個軟體是我們Allove Team開發的有一個生活小軟體,開始的定位就是天氣搜尋,後來我想擴充套件為“生活小助手”就是不但有世界天氣搜尋,還有出行參考,還有生活常識之類的東西。正在開發中。 由於,開發過程中需要使用Canvas才能做出很漂亮的介面,所以引發了一個老問題 — 手機鍵值!

很多人都說,要適配所有

手機的鍵值是不可能的。因為,已是J2ME中沒有對手機的左右軟鍵的鍵值定義,而是很多手機也沒定義,再者就是手機多多了,像華為,中興,聯想,諾基亞,摩托羅拉,西門子,索愛,黑莓,多普達等等這些大廠家都沒個定數,更別所多如牛毛的山寨機了,所以這種說法也是無可厚非的。 即使你把 左鍵 -7 , 右鍵 -6 , OK鍵 -5 這些都設定好能支援大部分的手機,還是難免有個害群之馬啊。 所以, 沒有標準導致了這個嚴重的問題 :要一次性搞定所有手機的鍵值問題難道非常之大。

但是,天知道我怎麼一生下來就是個不信邪的主兒,Google百度了幾下發現沒有統一鍵值之後開始思考自己的路了。最後,想了一個辦法,目的是我要一次性搞定所有手機的鍵值。怎麼做?讓使用者手機告訴你唄。思路如下:使用者第一次使用時設定鍵位。

  1. 用Canvas實現一個鍵位設定介面,捕獲keyPressed事件;
  2. 在設定介面中以提示性語言引導使用者按鍵;
  3. 將得到的鍵值儲存到RMS中備用;
  4. 完成鍵位設定;
  5. 在以後要使用按鍵的Canvas中呼叫RMS中的資料,完成操作。

下面是完成這個設定的簡要程式碼結構:

  1. //首先你需要一個數組:
  2. privateString[]drawArray = {"左功能鍵","右功能鍵","OK鍵","方向鍵【上】","方向鍵【下】","方向鍵【左】","方向鍵【右】"} ;
  3. //然後你需要兩個標誌位
  4. privatebooleanconfig_finished = false ;
  5. private
    booleanfirsttime = true ;
  6. //再者你需要一點實現邏輯
  7. if(drawIndex > 6){
  8. config_finished = true ;
  9. }
  10. if(!config_finished){
  11. if(firsttime){
  12. g.drawString("【鍵位設定】",WIDTH / 2 - titleWidht / 2 , startY, Graphics.TOP|Graphics.LEFT);
  13. g.drawString(initStr, 5, startY + 1*lineHeight, Graphics.TOP|Graphics.LEFT);
  14. g.drawString(prefix + drawArray[drawIndex] , 5, startY + 2*lineHeight, Graphics.TOP|Graphics.LEFT);
  15. }else{
  16. g.drawString("【鍵位設定】",WIDTH / 2 - titleWidht / 2 , startY, Graphics.TOP|Graphics.LEFT);
  17. g.drawString(initStr, 5, startY + 1*lineHeight, Graphics.TOP|Graphics.LEFT);
  18. g.drawString(finished + drawArray[drawIndex - 1] + status, 5, startY + 1*lineHeight, Graphics.TOP|Graphics.LEFT);
  19. g.drawString(prefix + drawArray[drawIndex] , 5, startY + 2*lineHeight, Graphics.TOP|Graphics.LEFT);
  20. }
  21. firsttime = false ;
  22. startY = 0 ;   
  23. initStr = "" ;
  24. }else{
  25. System.out.println("設定完畢 .... config finished ...");
  26. g.setColor(0xff0000);
  27. g.drawString("設定成功,請按OK鍵返回!", 5, startY + 4*lineHeight, Graphics.TOP|Graphics.LEFT);
  28. }
  29. //接下來我們需要一點控制信心和按鍵事件的響應
  30. protectedvoidkeyPressed(intkey){
  31. if(this.storeKeyValue(WHAT_KEY, key)){
  32. drawIndex ++ ;
  33. WHAT_KEY ++ ;
  34. status = "(成功)" ;
  35. }else{
  36. drawIndex -- ;
  37. WHAT_KEY -- ;
  38. prefix = "[重設]" ;
  39. status = "(失敗)" ;
  40. }
  41. if(config_finished && key == config.getOK()){
  42. System.out.println("read back of OK .. is " + config.getOK());
  43. wm.setThisAsCurrent(wm.getMainform());
  44. }
  45. repaint();
  46. }
  47. //最後我們需要一個儲存的動作
  48. privatebooleanstoreKeyValue(intwhatkey , intkey){}

請注意,上面這個程式碼片段只是完成按鈕設定的框架,而不是完整程式碼,如果你需要完整程式碼可以留下資訊並且發郵件告訴我。我會分享給你的。

下面說一下上面這段程式碼的大致思路:
建立一個你希望設定的鍵位的陣列:private String[] drawArray , 裡面存放著一些提示資訊,這些資訊用來引導使用者去按鍵,然後使用paint()在介面上繪製這些資訊,但又按鍵事件的時候系統會呼叫protected void keyPressed(int key)方法,而我們在這個方法中處理一些事件,不作一些控制。例如改變繪製字串的指標,例如修改鍵位設定的執行狀態 “成功” 或者 “失敗” 。 另外還需要控制的就是設定的完成狀態 , 最終目的是把鍵值寫入到RMS中備用 。

下面是鍵值呼叫的持久類的完整程式碼:

  1. packageorg.allove.weather.lib;
  2. publicclassKeyMap{
  3. ///////////////
  4. privatestaticKeyValueRmsconfig = KeyValueRms.getInstance();
  5. publicstaticfinalintkey_LeftSoft = config.getLeftSoft() ;
  6. publicstaticfinalintkey_RightSoft = config.getRightSoft() ;
  7. publicstaticfinalintkey_OK = config.getOK() ;
  8. publicstaticfinalintkey_UP = config.getUP() ;
  9. publicstaticfinalintkey_DOWN = config.getDown() ;
  10. publicstaticfinalintkey_LEFT = config.getLeft() ;
  11. publicstaticfinalintkey_RIGHT = config.getRight() ;
  12. ///////////////
  13. }

至於這個KeyValueRms 怎麼去實現就不是本文的主要內容了,這是RecordStore的內容,這裡就不贅述了 。

總的來說,我覺得這是一個很簡單的問題,也很容易想到,應該不到5分鐘吧,想到這個解決方案。由於我覺得這個東西很簡單,價值也不那麼明顯,所以導致了我看到一個東西之後很鬱悶。今天,無意中搜索鍵值玩,發現了萬方資料裡面的一片論文:《一種J2ME軟體適配不同手機鍵值的方法》讓我倍感無語。這個方法被人申請專利了,我很無語,這東西也能申請壯麗,我操,早知道我早兩年也去申請了。 還說得那麼玄乎,很糾結啊。

最後,要來說一下這個可行性和使用者體驗的問題。

  1. 其實這東西不是很好,完全依賴於keyPressed方法,如果不支援這個方法呢?
  2. 在某些手機中按左右軟鍵的時候是沒有反應的,比如巨頭諾基亞
  3. 再說使用者體驗,這個問題有點嚴重,一旦設定錯誤可能就需要從新安裝軟體,這是相當不友好的,因為RMS的資料要解除安裝才能清除,其實這個到也無所謂啦,你可以在軟體裡面做一個重新設定的功能,這到不致命
  4. 然後就是,不是所有使用者都能看懂你的引導語言,難免會設定錯誤,你不能保證每個使用者都是聰明的
  5. 由於手機廠商數目巨大,這個方法的代價是巨大的,慎用

拋棄這種方法之後如何去更快捷的適配不同手機的鍵值問題呢?也許按手機型號釋出軟體是一個最簡單最直接的方案,侷限性就是你必須知道每個平臺的鍵值,希望MIDP3.0不要再有這個問題了。現在,我們就假設,我們已經能夠獲取到不同手機的鍵值,那麼我們應該如何去寫程式碼呢?在每一個 keyPressed裡面設定switch case -6 / -7 / -5 的方法顯然是不對的。 我們希望這樣操作:

  1. packageorg.allove.weather.lib;
  2. publicclassKeyMap{
  3. ///////////////
  4. publicstaticfinalintkey_LeftSoft = -7 ;
  5. publicstaticfinalintkey_RightSoft = -6 ;
  6. publicstaticfinalintkey_OK = -5 ;
  7. publicstaticfinalintkey_UP = -4 ;
  8. publicstaticfinalintkey_DOWN = -3 ;
  9. publicstaticfinalintkey_LEFT = -2 ;
  10. publicstaticfinalintkey_RIGHT = -1 ;
  11. /////////////// 請注意 上面的鍵值只是為了測試 不一定正確
  12. }
  13. /////////////////////////////////////////
  14. // ..... Many Other Things ...
  15. importpackageorg.allove.weather.lib.KeyMap ;
  16. publicclassACanvasextendsCanvas ;
  17. // ..... Many Other Things ...
  18. protectedvoidkeyPressed(intkey){
  19. if(key == KeyMap.key_LeftSoft){
  20. do(.....) ;
  21. }elseif(key == KeyMap.key_OK){
  22. do(.....) ;
  23. }elseif(key == KeyMap.key_RightSoft){
  24. do(......) ;
  25. }
  26. repaint();
  27. }
  28. // ..... Many Other Things ...

相信這樣的程式碼結構是可讀的,方便維護的,容易移植的 。 當你需要移植平臺的時候只需要在KeyMap中修改對映即可。這也許就是OO思想的體現吧 。 好了今天就到這裡吧 , 上面的程式碼基本都是框架,如果你希望得到原始碼的話可以留言並且發郵件到sunjianyes#gmail.com獲取,如果你能記得我們Allove Team那就最好不過了。再如果你能夠支援一下我們的發展就更好了,最好的辦法就是嘗試使用我們的軟體: m.Allove.org
如果你在下次看到下面這張圖片的時候能想起我們那就是我們最大的成功: