最佳化J2ME應用程式 (轉)

gugu99發表於2007-12-09
最佳化J2ME應用程式 (轉)[@more@]

作者:Eric Giguere 編譯:Sean
2002年2月27號


如果要說應用和應用程式有什麼不同的地方的話,那就是他們各自被限制執行的環境。
很多J2ME的主要的瓶頸是和執行應用程式的可用數量。舉例來說,當前許多MIDP裝置,他們
限制給應用程式的記憶體數量就只有50K或更少,離可能要求兆級的基於服務端J2SE環境有段很長的距離。
由於你在開發中會很容易就遭遇這些限制,所以在這篇J2ME技術提示中,你會學到如何讓你的應用程式佔用最
少的記憶體。你將用這些技術減少MIDlet佔用的空間,MIDlet只是顯示一個文字框並且在其中內容被更改
的時候發出:
package com.j2medeveloper.tech;

import x.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 MainFoextends 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程式。
注意上面演示的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 Wireless Toolkit打包以後,這個MIDlet例子僅僅4K多一點。

減少size的第一步是透過減少應用程式功能來移除一些不必要的類。你的應用程式的每個特性都是真的必要的嗎?
你的能否忍受沒有鈴聲和哨聲?讓我們來建立最小版本的應用程式。注意到MIDlet例子已經是相當小的了。

第二步著眼於應用程式定義的內部類,特別是匿名類。記住每一個類都有一定相應的空間開支。甚至最微不足道的
類也需要成本:
  public class foo {
  // nothing here
  }
編譯這個類,你可以發現你得到一個佔用幾乎200位元組空間的class檔案。一個匿名類一般用途是用來實現事件。
MIDlet例子定義了兩個listener。一個簡單最佳化就是讓MIDlet的主類實現CommandListener和ItemStateListener
兩個介面,刪除裡面的listener程式碼。記住多個可以使用相同的listener。如果需要區別開來,
可以傳遞引數給commanAction和itemStateChanged方法。

內部類也會透過其他方面膨脹程式碼,因為必須產生不同的變數和方法來允許一個內部類訪問封裝類裡面的私有資訊。

第三步是最大程度使用內建的類。舉個例子,在基於CLDC的程式中不要建立你自己的集合類。儘量使用內建的Hashtable
和Vector。設計MIDP應用也是一樣。MIDlet例子定義了一個Form子類來建立它的主form,但它還能被很容易地直接建立:
  mainForm = new Form( "MainForm" );
  mainForm.addCommand( okCommand );
  mainForm.setCommandListener( listener );
這裡沒有對和錯的問題,這只是需要考慮的一些簡單的東西。

第四步是取消你應用程式的繼承關係。你可能已經將程式碼分解成一個或多個抽象類,這是個被推薦的能提高程式碼重用
的OOD設計方法。也許會跟你學到的東西有牴觸,但去簡化繼承層次更加說的過去。如果你的抽象類——可能來自其他專案——
只是被繼承了一次,那簡化繼承關係就顯得特別有理由。MIDlet例子擴充套件了BaicMIDlet類,但兩個類很容易組合成一個。

第五步是縮短你的包名,類名,方法名和資料成員名。看上去這一步顯得很愚蠢,但一個class檔案儲存了很多字元資訊。
縮短他們的名字你會減少clas檔案的size。這個辦法節省的東西不會很多,但當遍及到多個類時他們會增加。包名特別
應該被縮短。因為MIDP應用程式完全是獨立的,你能完全避免包名——不會有機會跟該裝置其他類的名字衝突。MIDlet例子
可以從com.j2medeveloper.techtips 包裡面移出來。

注意縮短名字不是你手工要做的那些東西,我們可以使用一個名叫“擾亂器”的工具來做。擾亂器的主要目的是
為應用程式“隱藏”程式碼,它反編譯程式的時候使程式變成一些幾乎無法閱讀的東西。這個過程的另外一個作用就是減少了程式的size。
那上因為隱藏程式碼主要透過重新為方法和資料成員命名。這裡有個開發的擾亂器叫RetroGuard的免費工具來自

最後,關注一些陣列的初始化。(MIDlet例子沒有做任何陣列初始化,但這是程式很重要的一步)當編譯完以後,一個陣列初始化
程式碼像這樣:
int arr[] = { 0, 1, 2, 3 };
實際產生的程式碼如下:
  arr[0] = 0;
  arr[1] = 1;
  arr[2] = 2;
  arr[3] = 3;
如果想研究的話,可以使用java2sdk一起釋出的將位元組程式碼分解成一個class的javap工具(使用-c引數)。你可能會驚訝和不滿
你所看到的結果。兩種可選的辦法是(1)把資料編碼到一個String裡面,執行時解碼到陣列,或(2)將資料作為二進位制檔案儲存
到程式包裡面並在執行時用class loader的getReourceAsStream方法訪問。

這裡說的東西只是一些指導,並且在這裡提到的不是每一步都適合每一個J2ME應用程式。然而,他們大部分都可以應用這個MIDlet例子。
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();
  }
  }
}

 


原文:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-990027/,如需轉載,請註明出處,否則將追究法律責任。

相關文章