MIDlet(ガラケーJavaアプリ、海外・ソフトバンク系)作成時の陥りやすいミス

10年ほど前の自分のメモを発掘したので念のため保存しておく。

Canvas

  • repaint()

repaint()はpaint要求を出しますが、必ずしもpaint()が実行されるとは限りません。呼ばれるタイミングはJavaVMに依存します。もしrepaint()を読んだタイミングで必ず画面更新を行いたければrepaint()の直後にserviceRepaints()も呼びましょう。

  • paint()

paint()の中で描画以外のことをするのはやめましょう。たとえばHTTP通信など。想定外の動きをすることがあります。

  • paint()

paintの引数のグラフィックスコンテキスト(Graphics g)をフィールド変数などに保存して別のメソッドから使用することは禁止されています。予期せぬ動作をする場合があるようです。

GameCanvas

  • paint()

GameCanvas.getGraphics(), flushGraphics()を使用しているならpaint()は空関数でオーバーライドしないほうがよいでしょう。
VMによってはrepaint()が自動でかかってpaint()→画面更新が走り、flushGraphics()で表示した内容を上書きしてしまう場合があるようです。

GameCanvas(true)はゲームキーをkeyPressedイベントとして取得しないようにするモード。getKeyStates()だけをゲームキー取得に使用するならtrueが良い(keyCode系、KEY_NUM0などはtrueにしても来る)が、keyPressedイベントでゲームキーも取りたいならfalseにする必要あり。

HTTP通信
HTTP通信は処理が占有されてしまうのでほかの処理も平行して動かすならThreadにしましょう。

Display

  • setCurrent()

setCurrent()はDisplayableのインスタンスを現在の画面に割り当てますが、呼び出してすぐ反映されるとは限りません(VM依存)。Thread.sleep()を入れるかDisplayable.isShown()で表示されていることを確認するまで次の処理に進まないようにしましょう。

補足として、CommandAction等のイベントリスナの中でisShown()を呼ぶとsetCurrent()がブロックされてしまい、いつまでたってもisShown()がTRUEにならないのでThreadなどで動かす等の工夫が必要です。

SpriteCanvas(JSCL, VSCL, MEXA)

drawFrameBuffer()はpaint()内で呼びましょう(というかMIDP1.0系のMIDletでは描画処理は基本的にpaint()内で行いましょう)。表示されなかったりすることがあります。

MIDlet

  • startApp() (JSCL, VSCL, MEXAの場合)

起動時の初期化の処理(画面の初期化など)を、startApp内に記述してしまう傾向がよく見受けられます。startApp()は、Resume時にも呼び出されてしまうので、初期化処理はコンストラクタ内に記述するか、Resume時に意図しない再初期化を引き起こさないようなガードを入れておく必要があります。

例)

 private boolean isRunning = false;
	
 protected void startApp() throws MIDletStateChangeException {
     if(!isRunning){
         Display display = Display.getDisplay(this);
         main = new Main(this);
         display.setCurrent(main);
         System.out.println("setCurrent finished!");
         new Thread(main).start();
         isRunning = true;
     } else {
         System.out.println("already running!");
     }
 }