J2ME開發的通常步驟

最近一段時間發現身邊有一本買了一年多的J2ME的書沒看,因而抱起來大概看了一下,個人E72是Symbian系統,支持J2ME,因此作了幾個簡單的小玩意。在學習J2ME開發的過程當中有一些簡單的心得和體會,如今寫下來備忘,若是有朋友也正在學習J2ME開發,以爲有幫助的話,那是最好不過的事情了。
 
1.開發環境安裝配置
目前開發J2ME應用的環境有多種,有基於NetBean的,不過仍以Eclipse爲主流。因此本篇以在Eclipse下開發J2ME來介紹。
1.1下載JDK
由於這些軟件自己是用Java開發的,因此首先須要去Java的官方網站下載JDK了,下載地址是:http://www.oracle.com/technetwork/java/javase/downloads/index.html,固然也能夠在國內正規網站下載,這樣能夠得到比較快的下載速度。
1.2下載Eclipse
最開始Eclipse僅僅是針對Java的,如今有不一樣開發場景下的插件,如JavaScript、PHP、C\C++、Java SE、Java EE及Java ME等,地址是:http://www.eclipse.org/downloads/,這裏選擇「Pulsar for Mobile Developers」,其下載地址是:http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/helios/R/eclipse-pulsar-helios-win32.zip。這是一個Zip文件,下載完成後若是安裝了JRE或者JDK便可雙擊Eclipse.exe使用。
 
2.插件安裝配置
在進行J2ME開發中,我的以爲比較有用的插件以下:
properties文件的Eclipse插件:http://propedit.sourceforge.jp/eclipse/updates
Coffee Bytes Java Folding Eclipse插件:http://eclipse.realjenius.com/update-site 
ExploreFS插件: http://www.junginger.biz/eclipse/
MTJ插件: http://download.eclipse.org/mtj/updates/1.1.2/stable
安裝插件的步驟以下(以安裝在Eclipse for J2SE爲例,在此基礎上添加J2ME插件):找到Eclipse界面上的Help->Install new software…->Add,在」name」處輸入」 JavaME」,在處輸入」 http://www.eclipseme.org/updates/ 」,以下圖:

點擊」OK」以後出現以下界面:
 

選擇要安裝的部分,再點擊」Finished」就能夠自動安裝相關插件。注意,視插件大小的不一樣,安裝的時間也會不一樣,不過通常時間都相對較長。
爲了不中文亂碼的問題,最好了解一下SDK對文件編碼的支持程度,通常來講爲了簡單起見,都是將文件編碼設置爲「UTF-8」,以下所示:
 

 
3.開發包安裝配置
目前比較流行的開發包有WTK(Wireless Toolkits)及各支持J2ME的手機廠商本身推出的SDK。若是針對某一類型的手機作開發,能夠直接去其官方網站下載SDK,像周公使用的是Nokia E72,它的SDK能夠在Nokia的官方網站下載S60 Platform SDKs for Symbian OS, for Java™的開發包,下載地址是: http://www.forum.nokia.com/info/sw.nokia.com/id/6e772b17-604b-4081-999c-31f1f0dc2dbb/S60_Platform_SDKs_for_Symbian_OS_for_Java.html。
注:關於插件的安裝及配置在周公的另外一篇文章《WinXP下搭建適合Nokia開發的J2ME環境》中有比較詳細的說明,網址是http://blog.csdn.net/zhoufoxcn/archive/2010/07/12/5728224.aspx
 
4.編碼及測試
這裏用來舉例的是一個簡單的例子,這是一個數字時鐘,爲此咱們須要準備12個圖片文件,分別用於時鐘繪製、錶盤及做爲應用程序的圖標。
項目體系結構以下:
 

MainMIDlet.java的代碼:
 
   
   
            
   
   
  1. package com.netskycn;  
  2. import javax.microedition.lcdui.Command;  
  3. import javax.microedition.lcdui.CommandListener;  
  4. import javax.microedition.lcdui.Display;  
  5. import javax.microedition.lcdui.Displayable;  
  6. import javax.microedition.midlet.MIDlet;  
  7. import javax.microedition.midlet.MIDletStateChangeException;  
  8. public class MainMIDlet extends MIDlet implements CommandListener{  
  9. private Display display;  
  10. private ImageCanvas canvas;  
  11. private Command cmdExit;  
  12. public MainMIDlet() {  
  13. super();  
  14. canvas=new ImageCanvas();  
  15. canvas.setTitle("周公數字時鐘");  
  16. cmdExit=new Command("退出", Command.EXIT, 0);  
  17. canvas.addCommand(cmdExit);  
  18. canvas.setCommandListener(this);  
  19. }  
  20. protected void destroyApp(boolean arg0) throws MIDletStateChangeException {  
  21. // TODO Auto-generated method stub  
  22. }  
  23. protected void pauseApp() {  
  24. // TODO Auto-generated method stub  
  25. }  
  26. protected void startApp() throws MIDletStateChangeException {  
  27. display=Display.getDisplay(this);  
  28. display.setCurrent(canvas);  
  29. }  
  30. public void commandAction(Command cmd,Displayable d){  
  31. if (cmd==cmdExit) {  
  32. notifyDestroyed();  
  33. }  
  34. }  
ImageCanvas.java的代碼:
 
   
   
            
   
   
  1. package com.netskycn;  
  2. import java.util.Calendar;  
  3. import javax.microedition.lcdui.Canvas;  
  4. import javax.microedition.lcdui.Graphics;  
  5. import javax.microedition.lcdui.Image;  
  6. public class ImageCanvas extends Canvas implements Runnable {  
  7. private Image[] p_w_picpaths;  
  8. private final int ImageCount=12;  
  9. private Calendar calendar=null;  
  10. //private byte hour,minute,second;  
  11. private int startX,startY;  
  12. private byte[] times=new byte[3];  
  13. public ImageCanvas(){  
  14. p_w_picpaths=new Image[ImageCount];  
  15. try {  
  16. for(int i=0;i<11;i++){  
  17. p_w_picpaths[i]=ZoomImage(Image.createImage("/p_w_picpaths/"+i+".JPG"),0.8d);  
  18. }  
  19. p_w_picpaths[11]=ZoomImage(Image.createImage("/p_w_picpaths/CLOCK.JPG"),0.8d);  
  20. startX=(getWidth()-p_w_picpaths[0].getWidth()*6-p_w_picpaths[10].getWidth()*2)/2;  
  21. startY=(getHeight()-p_w_picpaths[0].getHeight())/2;  
  22. catch (Exception e) {  
  23. System.out.println(e);  
  24. }  
  25. new Thread(this).start();  
  26. }  
  27. public void run() {  
  28. while (true) {  
  29. try{  
  30. repaint();  
  31. Thread.sleep(900);  
  32. }  
  33. catch (Exception e) {  
  34. System.out.println(e);  
  35. }  
  36. }  
  37. }  
  38. protected void paint(Graphics g) {  
  39. calendar=Calendar.getInstance();  
  40. // hour=(byte)calendar.get(Calendar.HOUR_OF_DAY);  
  41. // minute=(byte)calendar.get(Calendar.MINUTE);  
  42. // second=(byte)calendar.get(Calendar.SECOND);  
  43. times[0]=(byte)calendar.get(Calendar.HOUR_OF_DAY);//hour  
  44. times[1]=(byte)calendar.get(Calendar.MINUTE);//minute  
  45. times[2]=(byte)calendar.get(Calendar.SECOND);  
  46. g.drawImage(p_w_picpaths[11], (getWidth()-p_w_picpaths[11].getWidth())/2, (getHeight()-p_w_picpaths[11].getHeight())/2, Graphics.TOP|Graphics.LEFT);  
  47. int tenUnit,unit;  
  48. for(int i=0;i<times.length;i++){  
  49. tenUnit=times[i]/10;  
  50. unit=times[i]%10;  
  51. if(i==0){  
  52. g.drawImage(p_w_picpaths[tenUnit], startX, startY, Graphics.TOP|Graphics.LEFT);  
  53. g.drawImage(p_w_picpaths[unit], startX+p_w_picpaths[0].getWidth(), startY, Graphics.TOP|Graphics.LEFT);  
  54. g.drawImage(p_w_picpaths[10], startX+p_w_picpaths[0].getWidth()*2, startY+10, Graphics.TOP|Graphics.LEFT);  
  55. }  
  56. else if (i==1) {  
  57. g.drawImage(p_w_picpaths[tenUnit], startX+p_w_picpaths[0].getWidth()*2+p_w_picpaths[10].getWidth(), startY, Graphics.TOP|Graphics.LEFT);  
  58. g.drawImage(p_w_picpaths[unit], startX+p_w_picpaths[0].getWidth()*3+p_w_picpaths[10].getWidth(), startY, Graphics.TOP|Graphics.LEFT);  
  59. g.drawImage(p_w_picpaths[10], startX+p_w_picpaths[0].getWidth()*4+p_w_picpaths[10].getWidth(), startY+10, Graphics.TOP|Graphics.LEFT);  
  60. }  
  61. else {  
  62. g.drawImage(p_w_picpaths[tenUnit], startX+p_w_picpaths[0].getWidth()*4+p_w_picpaths[10].getWidth()*2, startY, Graphics.TOP|Graphics.LEFT);  
  63. g.drawImage(p_w_picpaths[unit], startX+p_w_picpaths[0].getWidth()*5+p_w_picpaths[10].getWidth()*2, startY, Graphics.TOP|Graphics.LEFT);  
  64. }  
  65. //g.drawImage(p_w_picpaths[tenUnit], startX, startY, Graphics.TOP|Graphics.LEFT);  
  66. }  
  67. //System.out.println("second="+times[2]);  
  68. }  
  69. /**  
  70.  * 圖像縮放算法  
  71.  * @param src 原始圖像  
  72.  * @param rate 圖像的縮放比率,縮放後的圖像高度和寬度都依照這個比率  
  73.  * @return  
  74.  */ 
  75. public static Image ZoomImage(Image src,double rate){  
  76. int destWidth=(int)(src.getWidth()*rate);  
  77. int destHeight=(int)(src.getHeight()*rate);  
  78. return ZoomImage(src, destWidth, destHeight);  
  79. }  
  80. /**  
  81.  * 圖像縮放算法  
  82.  * @param src 原始圖像  
  83.  * @param destW 縮放後的圖像寬度  
  84.  * @param destH 縮放後的圖像高度  
  85.  * @return  
  86.  */ 
  87. public static Image ZoomImage(Image src, int destW, int destH) {  
  88.     Image desImg = null;  
  89.     int srcW = src.getWidth();   
  90.     int srcH = src.getHeight();   
  91.     int[] srcBuf = new int[srcW * srcH];   
  92.     src.getRGB(srcBuf, 0, srcW, 00, srcW, srcH);  
  93.     int[] tabY = new int[destH];  
  94.     int[] tabX = new int[destW];  
  95.     int sb = 0;  
  96.     int db = 0;  
  97.     int tems = 0;  
  98.     int temd = 0;  
  99.       
  100.     int distance = srcH > destH ? srcH : destH;   
  101.       
  102.     for (int i = 0; i <= distance; i++) {   
  103.      tabY[db] = sb;  
  104.      tems += srcH;   
  105.      temd += destH;    
  106.      if (tems > distance) {  
  107.       tems -= distance;  
  108.       sb++;  
  109.      }  
  110.      if (temd > distance) {  
  111.       temd -= distance;  
  112.       db++;  
  113.      }  
  114.     }  
  115.     sb = 0;  
  116.     db = 0;  
  117.     tems = 0;  
  118.     temd = 0;  
  119.     distance = srcW > destW ? srcW : destW;   
  120.       
  121.     for (int i = 0; i <= distance; i++) {  
  122.      tabX[db] = (short) sb;  
  123.      tems += srcW;  
  124.      temd += destW;  
  125.      if (tems > distance) {  
  126.       tems -= distance;  
  127.       sb++;  
  128.      }  
  129.      if (temd > distance) {  
  130.       temd -= distance;  
  131.       db++;  
  132.      }  
  133.     }  
  134.     int[] desBuf = new int[destW * destH];  
  135.     int dx = 0;  
  136.     int dy = 0;  
  137.     int sy = 0;  
  138.     int oldy = -1;  
  139.     for (int i = 0; i < destH; i++) {  
  140.      if (oldy == tabY[i]) {  
  141.       System.arraycopy(desBuf, dy - destW, desBuf, dy, destW);  
  142.      } else {  
  143.       dx = 0;  
  144.       for (int j = 0; j < destW; j++) {  
  145.        desBuf[dy + dx] = srcBuf[sy + tabX[j]];  
  146.        dx++;  
  147.       }  
  148.       sy += (tabY[i] - oldy) * srcW;  
  149.      }  
  150.      oldy = tabY[i];  
  151.      dy += destW;  
  152.     }  
  153.     desImg = Image.createRGBImage(desBuf, destW, destH, false);  
  154.     return desImg;  
  155.  }  
因爲今天要講述的重點不是如何編寫J2ME應用,而是這種講述整個流程,因此這裏不對代碼作過多解釋。
 
5.更改有關應用程序的信息
上面的代碼能編譯經過而且能在Symbian系列手機上運行,不過若是你就此將生成的jar包拷貝到手機上安裝運行,會看到相似下面的效果:
 

這是由於關於這個J2ME應用不少仍是採用了默認設置,爲了讓咱們的應用不同凡響,咱們應該作一些特有的設置,好比設置應用的logo及應用名稱等,這些能夠在Eclipse中很方便地設置。打開項目中的「Application Descriptor」文件,而後打開「Application Descriptor」選項卡,以下:
 

此時這個文件的內容爲:
MIDlet-Version: 1.0.0
MIDlet-Vendor: MIDlet Suite Vendor
MIDlet-Jar-URL: DigitalClock.jar
MicroEdition-Configuration: CLDC-1.1
MIDlet-1: MainMIDlet,,com.netskycn.MainMIDlet
MicroEdition-Profile: MIDP-2.0
MIDlet-Name: Zhou
咱們把它改成:
MIDlet-1:  卡通時鐘,/p_w_picpaths/logo.png,com.netskycn.MainMIDlet
MIDlet-Jar-URL: DigitalClock.jar
MIDlet-Icon: /p_w_picpaths/logo.png 
MicroEdition-Configuration: CLDC-1.1
MIDlet-Version: 1.0.0
MIDlet-Name:  卡通時鐘
MIDlet-Description:  卡通時鐘
MIDlet-Vendor:  周公
MicroEdition-Profile: MIDP-2.0
在上面的文本中紅色加粗部分是新增的,僅僅標識爲紅色的是在原有基礎上作的修改。這樣一來咱們的應用程序安裝以後就能夠顯示咱們指定的名稱和圖標了,以下圖所示:
 

6.代碼混淆
上面的代碼確實可以很好的運行,可是因爲運行在虛擬機之上的語言都有一個特色,那就是由於比較高級的緣由因此很容易被反編譯,若是你的點子很好,人家能夠經過反編譯工具查看你的代碼,「借鑑」或者篡改程序代碼以達到不可告人的目的(這一點國內的*壩及一些所謂開源的操做系統和國產數據庫作得很好,「借鑑」得至關成功,聽說有的都進入「核高基」了)。做爲公司和我的來講天然不但願出現這樣的狀況,避免這種狀況有幾種辦法:加殼、加密和混淆。相對來講,混淆是反作用最小的一種,於是也被廣泛接受。ProGuard是一款不錯的開源混淆工具,它的下載地址是: http://proguard.sourceforge.net/。
將下載的文件解壓到一個文件下,而後在Ecplise中作以下配置:
 

7.應用程序打包
剛剛咱們已經設置了ProGuard,的根路徑,下面咱們來將如何使用。首先選中要打包的項目,而後鼠標右鍵,選擇「Export...」,這時候出現以下界面:
 

選中「Export Midlet Package」而後點擊「Next」,出現以下界面:
 

在上圖中選中「Obfuscate the code」後,打包後的應用程序代碼就被混淆了,混淆代碼除了是代碼更難懂以外,還能夠必定程度上減小打包文件的體積。
總結:這是一個周公這幾個星期來學習J2ME開發的一個總結,偏重於流程的介紹,關於如何設置應用程序安裝後的問題和圖標問題周公是費了很大心思才弄明白的。做爲備忘,周公寫了這篇文章,若是你當前也在學習J2ME開發的初級階段,或許也能有一點參考價值。周公正在琢磨基於微博的應用,若是有興趣,請在新浪微博上圍觀,地址是:http://weibo.com/zhoufoxcn
周公
2011-06-12
相關文章
相關標籤/搜索