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