游戲策劃咨訊
          做一個游戲并不難,難的是做一個好游戲;完美在于積累!

          要把J2ME程序與J2SE程序區分開來,其依據就是J2ME運行所處的受限環境。多數J2ME系統的主要受限條件就是可以存儲和運行程序所需內存的大小。例如,許多MIDP設備限制應用程序的尺寸不大于50K,這遠遠不及Server端J2SE運行環境下那些成兆的程序。實際應用中,程序會很容易超出這些限制條件。通過本篇您將學到一些減小程序尺寸大小的技巧,并在下面的例子中實踐這些技術。這個例子MIDlet僅僅顯示一個文本框并在其內容改變時發聲。

          package com.j2medeveloper.techtips; 
          import javax.microedition.lcdui.*; 
          public class BeforeSizeOptimization extends 
                                                BasicMIDlet { 
           public static final Command exitCommand = 
                                new Command( "Exit", 
                                           Command.EXIT, 1 ); 
           public BeforeSizeOptimization(){ 
           } 
           protected void initMIDlet(){ 
               getDisplay().setCurrent( new Mainform() ); 
           } 
           public class Mainform extends form { 
               public Mainform(){ 
                   super( "Mainform" ); 
                   addCommand( exitCommand ); 
                   append( textf ); 
                   setCommandListener( new CommandListener(){ 
                       public void commandAction( Command c, 
                                              Displayable d ){ 
                           if( c == exitCommand ){ 
                               exitMIDlet(); 
                           } 
                       } 
                     } 
                   ); 
                   setItemStateListener( 
                                     new ItemStateListener() { 
                       public void itemStateChanged( 
                                                  Item item ){ 
                           if( item == textf ){ 
                               AlertType.INFO.playSound( 
                                               getDisplay() ); 
                           } 
                       } 
                     } 
                   ); 
               } 
          
               private TextField textf = 
                         new TextField( "Type anything", null, 
                                        20, 0 ); 
           } 
          }


          雖然這個MIDlet在此僅作為一個例子,但使用的尺寸優化技巧可以適用于任一J2ME的profile上。


          注意,上面的MIDlet類需要下面的輔助類:

          package com.j2medeveloper.techtips; 
          import javax.microedition.lcdui.*; 
          import javax.microedition.midlet.*; 
          public abstract class BasicMIDlet extends MIDlet { 
           private Display display; 
           public BasicMIDlet(){ 
           } 
           protected void destroyApp( boolean unconditional ) 
                           throws MIDletStateChangeException { 
               exitMIDlet(); 
           } 
           public void exitMIDlet(){ 
               notifyDestroyed(); 
           } 
           public Display getDisplay(){ return display; } 
           protected abstract void initMIDlet(); 
           protected void pauseApp(){ 
           } 
           protected void startApp() 
                           throws MIDletStateChangeException { 
               if( display == null ){ 
                   display = Display.getDisplay( this ); 
                   initMIDlet(); 
               } 
           } 
          }


          用J2ME WTK打包時,本例子MIDlet占用4K空間。


          減小尺寸的首要步驟就是通過修正程序的功能實現來去掉多余的類。程序的所有功能確實必須都實現嗎?用戶可以不需要這些“附屬功能”嗎?要設計盡可能小的程序,這里的MIDlet例子已經相當小了。

          第二步就是深入考察程序定義的內部類,特別是匿名類。記住,每個類文件都有一定量的與之相關的系統開銷。即便最普通的類也有系統開銷。

          public class foo { 
               // nothing here 
           }


          編譯上邊的類,生成的類文件大約200byte大小。比如實現一個事件監聽器,就是對匿名類的常見使用。在例子MIDlet中就定義了兩個此類的監聽器。接下來進行的最簡單的優化就是,讓主MIDlet類實現CommandListener和ItemStateListener接口,并把監聽器代碼移至此處。記住,多個對象可以使用同樣的監聽器。必要時,可以使用傳遞至commandAction和itemStateChanged方法的參變量來區分它們。

          內部類也可使代碼過大,因為編譯器必須生成特殊的變量和方法,以便內部類可以訪問包含它們的類的私有內容。請參考內部類的規范以獲取更多信息。

          第三步,盡量使用現有的類。例如,基于CLDC的profile沒有構造集合類,所以我們可以用內建的Hashtable和Vector類來實現之。構造MIDP程序時也可采用此法。例子MIDlet中定義了一個form字類來生成主表,可以容易的如下直接生成:

          mainform = new form( "Mainform" ); 
           mainform.addCommand( okCommand ); 
           mainform.setCommandListener( listener );


          這里沒有正確或者錯誤的答案,只是要推敲。

          第四步就是破壞程序的繼承關系。你也許把相關的代碼放到一個或多個抽象類中,這是OOD中為提高程序間代碼重用的推薦做法。雖然破壞繼承關系與你所學知識相違背,但簡化的繼承關系更有意義。特別的,當你的的抽象類――可能來自其他項目――僅僅被繼承一次時,破壞繼承關系的結果不言而喻。例如,例子MIDlet繼承了BasicMIDlet類,但兩者合并為一個類。

          第五步就是要縮短名字長度,如包名、類名、方法名和數據元素名??雌饋碛行┐?,但一個類文件確實包含太多的符號信息。縮短各量的名字可以縮小生成的類文件尺寸。這種節省不會特別明顯,但多個類中進行總加的結果還是可觀的。包名對減小尺寸來講特別合適。MIDP程序是完全自我包容的,完全可以不使用包名,因為在手持設備上包名根本不可能與其他類名沖突。例子MIDlet中,可以把com.j2medeveloper.tchtips包名去掉。

          注意,一般來講,縮短名字不需要手工去做,要用一個“混淆器”去做?!盎煜鳌钡闹饕δ苁恰半[藏”程序代碼,使之不能通過反編譯讀出。它的副作用是減小了程序的尺寸。因為隱藏過程主要通過更改方法和數據成員的名字來完成。有一個開源的混淆器稱為RetroGuard,可以免費從http://www.retrologic.com得到。也有一些商業包可用。(當為基于CLDC的profile混淆時,記得在預校驗之前混淆,否則混淆器將使類文件中的預校驗數據失效。)

          最后,深入數組的初始化。(例子MIDlet沒有做數組初始化,但對程序來說初始化是重要的一步) 在編譯時,一個數組初始化聲明如下所示:

          int arr[] = { 0, 1, 2, 3 }; 
          而實際生成代碼的過程如下所示: 
          <ccid_nobr>
          <table width="400" border="1" cellspacing="0" cellpadding="2" 
           bordercolorlight = "black" bordercolordark = "#FFFFFF" align="center">
          <tr>
              <td bgcolor="e6e6e6" class="code" style="font-size:9pt">
              <pre><ccid_code> arr[0] = 0; 
           arr[1] = 1; 
           arr[2] = 2; 
           arr[3] = 3;


          這個過程可以通過使用Java 2 SDK中附帶的javap工具把二進制代碼反編譯成類文件去看(使用-c選項)。也許你會詫異于看到的內容,特別當你希望看到的是一排排二進制常數時。有兩種方法可以讓你看不到反編譯的程序代碼,(1)把數據編碼為字符串,運行時解碼之,或者(2)把數據存為二進制文件并與程序打包,用類裝載器的getResourceAsStream方法在運行時存取之。

          以上只是一些指導性的方法,對每個J2ME程序而言,這里沒有具體到步驟。但是多數方法可以應用的本例。優化后的MIDlet如下所示:

          import javax.microedition.lcdui.*; 
          import javax.microedition.midlet.*; 
          public class ASO extends MIDlet 
                        implements CommandListener, 
                                   ItemStateListener { 
           private Display   display; 
           private form      mainform; 
           private TextField mainformTF = 
                         new TextField( "Type anything", null, 
                                        20, 0 ); 
           public static final Command exitCommand = 
                                new Command( "Exit", 
                                            Command.EXIT, 1 ); 
           public ASO(){ 
           } 
           public void commandAction( Command c, 
                                      Displayable d ){ 
               if( c == exitCommand ){ 
                   exitMIDlet(); 
               } 
           } 
           protected void destroyApp( boolean unconditional ) 
                           throws MIDletStateChangeException { 
               exitMIDlet(); 
           } 
           public void exitMIDlet(){ 
               notifyDestroyed(); 
           } 
           public Display getDisplay(){ return display; } 
           protected void initMIDlet(){ 
               mainform = new form( "Mainform" ); 
               mainform.addCommand( exitCommand ); 
               mainform.setCommandListener( this ); 
               mainform.setItemStateListener( this ); 
               mainform.append( mainformTF ); 
               getDisplay().setCurrent( mainform ); 
           } 
           public void itemStateChanged( Item item ){ 
               if( item == mainformTF ){ 
                   AlertType.INFO.playSound( getDisplay() ); 
               } 
           } 
           protected void pauseApp(){ 
           } 
           protected void startApp() 
                           throws MIDletStateChangeException { 
               if( display == null ){ 
                   display = Display.getDisplay( this ); 
                   initMIDlet(); 
               } 
           } 
          }


          關于作者:Eric Giguere是來自Sybase下屬iAnywhere Solutions的軟件開發人員。他致力于手持設備和無線計算領域的Java技術。他是滑鐵盧大學的數學學士和數學碩士,寫了很多有關計算的文章。

          posted on 2005-02-20 18:21 藍色雪焰 閱讀(291) 評論(0)  編輯  收藏 所屬分類: 編程技術
           
          主站蜘蛛池模板: 东明县| 凤台县| 靖宇县| 田东县| 正镶白旗| 固阳县| 鄂托克前旗| 华阴市| 博白县| 茂名市| 古浪县| 甘泉县| 合肥市| 高台县| 郎溪县| 萨迦县| 隆子县| 朝阳区| 舟曲县| 双鸭山市| 武胜县| 尼木县| 金沙县| 斗六市| 托里县| 乌拉特前旗| 宿松县| 左权县| 潞西市| 荥阳市| 专栏| 宣汉县| 吉水县| 静乐县| 玉溪市| 乐陵市| 奎屯市| 和平县| 那曲县| 巨鹿县| 霍邱县|