S-JIS[2004-11-23/2005-12-31]
iアプリもjavaであることには変わりないので、覚えることは独特のクラスだけ。と思いたい…。
普通のJavaアプリケーションの場合、javaコマンド実行時に指定したクラスのmain関数が最初に実行される。
iアプリの場合、com.nttdocomo.ui.IApplicationを継承したクラスのpublic void
start()メソッドが最初に実行されるらしい。
(どのクラスを実行するかは別途指定するみたいだけど)
package jp.hishidama.iappli; import com.nttdocomo.ui.IApplication; public class Hello extends IApplication { /* (非 Javadoc) * @see com.nttdocomo.ui.IApplication#start() */ public void start() { // TODO 自動生成されたメソッド・スタブ } }
Eclipseから普通のJavaアプリケーションを実行する方法と同様。
主な違いは、「実行(N)」ダイアログの「構成(F)」ペインで「DoJa-3.0 アプリケーション」を選ぶこと。
でもそのまま実行しても、コンソールに「AppName の値がありません」とエラーが表示されるだけだけど…。
これは、iアプリ独特の「jamファイル」とかいうのが足りない所為らしい。(JAM:Java Application
Manager)
Eclipseには、jamファイルを編集する為の特別なツールは無い。普通のEclipseのテキストエディタで編集する。
Eclipseのワークスペースの下の「プロジェクト名/bin」の下に、「プロジェクト名と同じ名前.jam」というファイルがある。
最初はパッケージエクスプローラーで見ても見えないかもしれないけど、binを右クリックして「最新表示(F)」すると出てくる。
この中に、必要なものを書いてやる。(並び順は勝手に変更されるので、どこに書いてもOK)
LastModified = Tue, 23 Nov 2004 13:37:53 AppClass = jp.hishidama.iappli.Hello AppName = ひしだまiアプリtest PackageURL = iTest.jar AppSize = 723
名前 | 説明? | 例 |
---|---|---|
AppClass | 実行するクラス。パッケージがある場合はそれも書かないと、ClassNotFoundException。 | jp.hishidama.iappli.Hello |
AppName | アプリケーションの名前。携帯にダウンロードした際、iアプリのメニューに表示される。 | ひしだまiアプリtest |
LastModified | jarファイルの最終更新日時らしい。Eclipseから実行すると、勝手に変わる。 | |
PackageURL | プログラムが格納されたjarファイルっぽい。勝手に書かれている。jarファイルのファイル名はEclipseのプロジェクト名になる模様。このjarファイル本体は、「プロジェクト名/bin」の下に作られる。 | iTest.jar |
AppSize | どうも、PackageURLで指定しているjarファイルのサイズ[BYTE]っぽい。勝手に変わる。 | |
UseNetwork | ネットワークを使用する際に指定が必要。[2005-12-03] | UseNetwork = http |
SPsize | 使用するスクラッチパッドのサイズ[BYTE]を指定。スクラッチパッドを使う場合は必須っぽい。[2005-12-31] | SPsize = 10240 |
import com.nttdocomo.ui.*; 〜 public void start() { System.out.println("start"); Panel panel=new Panel(); panel.add(new Label("Hello,world")); Display.setCurrent(panel); System.out.println("end"); }
パネルのインスタンスを作り、文字列を表示するためのラベルを作ってパネルに入れ、最後にそのパネルを表示しているという感じだろうか。
System.out.println()の出力先は、Eclipseのコンソール。
なお、例外発生時のprintStackTrace()では、普通のjavaと違ってソースの位置や呼び出し履歴は出力されなかった…すこぶる不便。
public class Hello extends IApplication { /* (非 Javadoc) * @see com.nttdocomo.ui.IApplication#start() */ public void start() { System.out.println("start"); Frame frm=new HelloCanvas(); System.out.println("display"); Display.setCurrent(frm); System.out.println("end"); } } class HelloCanvas extends Canvas { /* (非 Javadoc) * @see com.nttdocomo.ui.Canvas#paint(com.nttdocomo.ui.Graphics) */ public void paint(Graphics g) { System.out.println("paint_start"); g.lock(); g.setColor(Graphics.getColorOfName(Graphics.BLUE)); g.drawString("Hello,canvas",16,32); g.unlock(true); System.out.println("paint_end"); } }
ちなみに、コンソールへのログの出力順は、ちょっと不思議。start()の中で処理が完結しているわけではないみたい。きっと、paint()は実際に画面に表示されるときに呼ばれるんだろうな。(VC++でOnDraw(CDC *pDC)が呼ばれるのと同じようなもの?)
start display end paint_start paint_end
Display#setCurrent()に渡すフレームを変えてやれば切り替えられるみたい。
IApplicationの派生クラス:
public class Hello extends IApplication { /* (非 Javadoc) * @see com.nttdocomo.ui.IApplication#start() */ public void start() { Display.setCurrent(new HelloPanel()); //最初はパネルを表示 } }
パネルの派生クラス:
public class HelloPanel extends Panel implements SoftKeyListener { /** * コンストラクター */ public HelloPanel() { //タイトル setTitle("パネルのテスト"); //ソフトキーの初期化 setSoftLabel(SOFT_KEY_1, "CHG"); setSoftLabel(SOFT_KEY_2, "QUIT"); setSoftKeyListener(this); //ソフトキーの処理に自分(SoftKeyListenerの派生クラス)を登録 //レイアウトマネージャーを無効化 setLayoutManager(null); //ラベルを付けてみる Label label = new Label("パネルのラベル"); label.setForeground(Graphics.getColorOfName(Graphics.BLUE)); label.setLocation(32, 48); //←レイアウトマネージャーを無効にしていないと無視される super.add(label); } /* (非 Javadoc) * @see com.nttdocomo.ui.SoftKeyListener#softKeyPressed(int) */ public void softKeyPressed(int softKey) { switch (softKey) { case SOFT_KEY_1 : Display.setCurrent(new HelloCanvas()); //キャンバスへ切り替え break; case SOFT_KEY_2 : IApplication.getCurrentApp().terminate(); //アプリケーション終了 break; } } /* (非 Javadoc) * @see com.nttdocomo.ui.SoftKeyListener#softKeyReleased(int) */ public void softKeyReleased(int softKey) { } }
キャンバスの派生クラス:
public class HelloCanvas extends Canvas { /** * コンストラクター */ public HelloCanvas() { //ソフトキーの初期化 setSoftLabel(Frame.SOFT_KEY_1, "CHG"); setSoftLabel(Frame.SOFT_KEY_2, "QUIT"); } /* (非 Javadoc) * @see com.nttdocomo.ui.Canvas#paint(com.nttdocomo.ui.Graphics) */ public void paint(Graphics g) { g.setColor(Graphics.getColorOfName(Graphics.AQUA)); g.drawString("キャンバスの文字列", 16, 16); } /* (非 Javadoc) * @see com.nttdocomo.ui.Frame#processEvent(int, int) */ public void processEvent(int type, int param) { if (type == Display.KEY_PRESSED_EVENT) { switch (param) { case Display.KEY_SOFT1 : Display.setCurrent(new HelloPanel()); //パネルへ切り替え return; case Display.KEY_SOFT2 : IApplication.getCurrentApp().terminate(); //アプリケーション終了 return; } } super.processEvent(type, param); } }
public class MoveCanvas extends Canvas implements Runnable { private int x, y; private int k, zk; private java.util.Random rnd = new java.util.Random(); /** * コンストラクター */ public MoveCanvas() { x = 0; y = getHeight() / 2; k = 0; //背景色を指定 setBackground(Graphics.getColorOfName(Graphics.BLACK)); //自分自身のスレッドを作成 Thread runner = new Thread(this); //java.lang.Thread runner.start(); //スレッド実行開始 } /* (非 Javadoc) * @see com.nttdocomo.ui.Canvas#paint(com.nttdocomo.ui.Graphics) */ public void paint(Graphics g) { g.lock(); g.clearRect(0, 0, getWidth(), getHeight()); final int r = 24; g.setColor(Graphics.getColorOfName(Graphics.YELLOW)); g.fillArc(x - r / 4, y - r / 4, r, r, k, 360 - k * 2); //g.fillRect(x - r / 2, y - r / 2, r, r); g.unlock(true); } /* (非 Javadoc) * @see java.lang.Runnable#run() */ public void run() { while (true) { try { Thread.sleep(10); } catch (InterruptedException e) { } //ドットを動かす if (++x >= getWidth()) { x = 0; } if ((rnd.nextInt() & 1) == 0) { if (--y < 0) { y = getHeight() - 1; } } else { if (++y >= getHeight()) { y = 0; } } //角度を変更する if (k <= 4) { zk = 2; } else if (k >= 45) { zk = -4; } k += zk; //再描画を指示 super.repaint(); //キー判定 int key = super.getKeypadState(); if ((key & (1 << Display.KEY_SELECT)) != 0) { IApplication.getCurrentApp().terminate(); //アプリケーションの終了 } } } }
画像は、gif形式を扱える。プロジェクト配下の「res」ディレクトリに置いておけば、ビルド時にjarファイル内にコピーされる。そこからアプリ実行時に読み込み可能。
private Image loadImage(String name) { MediaImage mi = MediaManager.getImage("resource:///" + name); try { mi.use(); } catch (ConnectionException e) { e.printStackTrace(); System.err.println("conn:" + name); } catch (UIException e) { e.printStackTrace(); System.err.println("ui:" + name); } return mi.getImage(); }
このメソッドでは、引数nameにファイル名を渡す。
もし「res/img/hoge.gif」というディレクトリで画像を置いていれば、nameには「img/hoge.gif」を渡せばよい。
単なるデータは、以下のようにして読み込む。[2005-12-03]
public byte[] loadData(String name, long offset, int len){ try { InputStream is = Connector.openInputStream("resource:///" + name); is.skip(offset); byte[] buf = new byte[len]; is.read(buf); is.close(); return buf; } catch (IOException e) { e.printStackTrace(); System.err.println("io:" + name); } }
このメソッドでは、引数nameにファイル名、offsetとlenには読み込む位置と長さを指定する。
もし「res/data.dat」というファイルを先頭から256バイト読みたければ、「byte[] data = loadData("data.dat", 0,
256);」となる。
ネットワーク経由でhttpでデータを取得する場合、以下のようにして読み込む。[2005-12-03]
public byte[] getHttpData(String name) { String url = this.getSourceURL() + name; try { HttpConnection conn = (HttpConnection)Connector.open(url, Connector.READ, true); conn.setRequestMethod(HttpConnection.GET); conn.connect(); InputStream is = conn.openInputStream(); byte[] buf = new byte[(int)conn.getLength()]; is.read(buf); is.close(); conn.close(); return buf; } catch (Exception e) { Dialog d = new Dialog(Dialog.DIALOG_ERROR, "サーバーファイル取得エラー"); d.setText(url + "\n" + e.toString()); d.show(); return null; } }
IApplication#getSourceURL()を使うと、アプリをダウンロードした場所のURLが取得できる。
つまりダウンロード用のjarファイルと同じ場所にデータファイルを置いておけば、上記の方法でファイルを読み込める。
(ただし、Eclipseからエミュレータで動かす場合は「/」しか返ってこないのでurlが正しくならず、エラーになるが…)
それから、ネットワークを使用する際にはjamファイルに「httpを使用する」という指定をする必要がある。
UseNetwork = http
この指定が無いと、「UseNetworkというキーがADF(jamファイルのこと)に無い」という例外が発生する。
java.lang.SecurityException: UseNetwork key not found in ADF
この指定を入れると、実機でアプリケーションを動かす際に通信するかどうか(ネットワークを使用するかどうか)を聞いてくる。
ここで「使用する」を選択すれば通信できるが、「使用しない」を選択すると以下のような例外が発生し、通信できない。
java.lang.SecurityException: User selected not use network
アプリケーションが終了しても保持しておきたいデータは、スクラッチパッドに保存して読み込める。[2005-12-31]
アプリケーションのjarサイズにも制限があるので、固定データを 初回はhttpから取得してスクラッチパッドに書き込み、次回以降はスクラッチパッドから読み込む…という事もできるんだけど、アリかなぁ?
/** スクラッチパッドから画像を取得する */
public Image getScratchImage(int pos) {
try {
MediaImage mi = MediaManager.getImage("scratchpad:///0;pos=" + pos);
mi.use();
return mi.getImage();
} catch(Exception e) {
Dialog d = new Dialog(Dialog.DIALOG_ERROR, "スクラッチイメージ取得エラー");
d.setText(pos + "\n" + e.toString());
d.show();
return null;
}
}
/** スクラッチパッドへデータを保存する */
public void saveScratchData(int pos, byte[] data) {
try {
OutputStream os = Connector.openOutputStream("scratchpad:///0;pos=" + pos);
os.write(data);
os.close();
} catch(Exception e) {
Dialog d = new Dialog(Dialog.DIALOG_ERROR, "スクラッチ保存エラー");
d.setText(pos + "\n" + e.toString());
d.show();
}
}
読み込みでも書き込みでも、「scratchpad:///0;pos=0」といった文字列を指定することでアクセスできる。
スクラッチパッドを使用する際にはjamファイルに「スクラッチパッドサイズ」を指定する必要がある。
SPsize = 10240
この指定が無いと、「レングス不正」という例外が発生する。
java.io.Exception: Illegal length