デベロッパ Tech Cradle - BREW / 携帯 Java 技術情報 -

リンク: デベロッパ Tech Cradle - BREW / 携帯 Java 技術情報 -.

 ソフィアクレイドルのBREWでのC++コーディングに関する技術ノウハウなど。

 ちぇっく。

 つーかですね。ここまでしてC++使わなくてもいいんじゃね?とか思うわけですが。過激なこと言うと、お前らコンパイラにお世話してもらわないとカプセル化ひとつできねーのかよ、と。

| | コメント (0) | トラックバック (0)

BREWの記事が書けない訳

 「ゲーム屋のためのBREW開発のキモ」という記事が頓挫している。

 もうモノの見事な尻切れトンボ。竜頭蛇尾。三日坊主ぶり。であるw

 実はあの記事を書いた少し後に「KDDIの正規開発者用ドキュメント」を手に入れられる資格を得たのだが、その公開用のものとは段違いの情報量にビックリw

 をいをい。こんなに違うのかよ、と。

 当然、開発者としてはそっち(正規版)に知識をリプレースするわけだが・・・。

 公開版の知識と正規版の知識がごっちゃになって、記事が書けませーんwww

 正規版は、当然NDAを結んで手に入れているわけであるから、ブログに書くわけにはいかない。書けるのは公開用の資料に基づいた記事のみ。しかもその記事は古かったり、間違っていたりで、どうしたもんだか・・・って感じ。

 BREWも3.xに上がって、ますます公開用資料は役に立たなくなっていってるしw 正直、開発者は公開用の資料を元にプログラミングしないほうがいいと思う。例えば、BREWで作った画像を待ち受け画面に転送できるかどうか公開用資料では判らない、とか。どういったものが作れるのかでさえ図るのが難しい。KDDIはどうやらこれ以上BREW開発者を増やしたくないらしいw

 そんなわけで、どう記事を書くべきか思案中である。BREWの仕事も一段落したので、経験を踏まえて書けることをぼちぼち整理しているので、もうちょっと待ってください。もう待ってる人いないだろうけどwww

| | コメント (2) | トラックバック (0)

なにげにhirax.netにリンクされててうわああああっ

 コレ

 がむばります。

| | コメント (0) | トラックバック (0)

ポインタテーブル使えませんかそうですか

 BREWに新たな発見。ポインタテーブル作れません!
 実行してからプログレッシブに作ることは可能なんだが、静的にテーブルを用意しておくのはダメだとさ。

const int foo = 1;
const int bar = 2;
const int * const tbl[] = { &foo, &bar };
↑ダメな例

 アンナァ・・・。ポインタテーブルなんてそこら中で必要だっつ-の。関数テーブルとかどうすんのよ。switch/caseでやれってか? それともC++で継承でござんすかい?
 一次が可変長な二次元テーブルとかもポインタテーブルでやるんですがね・・・。

 いろいろ調べてみて、原因はどうやら完全リロケータブルなコードにしておかなければいけないかららしい。つまり、実行時スタートアドレスが不明のため、リンカでアドレス解決できないものは全て×だと。だから、上記の例がstaticになっていると、PC相対でアドレスを決定できるので、OKになることがある(場所が遠くなったらダメ)。externalなシンボルは全部ダメ。

 やっかいなことに、エミュレータ上だとOKなんだよな。VC++でIntelコードだから。ARMコンパイラだとダメになる。だから、エミュレータ上でガンガンポインタテーブルを用意して、いざARMでビルドすると、鬼のようなエラーが!!! ぎゃああああぁぁぁ・・・・(憤死) 
 それにしても、エミュレータ上と実機上でマシンコードが異なる環境ってのはどうなのよ?

 他にもARMの自動make生成がANSI C strictなもんだから、warning吐く々々w ビットフィールドはintでないとダメだとか、()は(void)にしろだとか、warning撲滅運動員のワタクシと致しましては、売られたケンカ(warning)は買わなきゃ収まらねぇ。ま、makeを手で書き換えりゃいいんだけどね。メンドクセーANSI C の勉強にもなる からそのまんま。

 グローバル変数の問題は、GETAPPINSTATNCE()を引っ張ってくることで解決しそうなんだが、その関数(マクロ?)も機種依存で無効になることがあるらしく、おーまいごっです。

 とりあえず、御約束のassert()とかデバッグ用printf()とか(ほんのちょっぴり)安全なmalloc()/free()とか便利マクロを作る日々。なんかプラットフォームが新しくなるたびに作っているような気がするアルよw

| | コメント (0) | トラックバック (0)

Path最大長の罠

 をいをい。まだそんなものがあるのかよ・・・。

 というわけで、「CodeWarriorとJavaSDKと、Nokia開発スイートと、ARM開発スイートを入れたら、ユーザーPATHが取り込めなくなって、VisualStudioがコマンドで呼べなくなる罠」に嵌りかけますたw
 全てはARM様がクソ深いフォルダ構成で、クソ長いpathを登録したおかげでございます。これだから、毛党は頭がうわなにおするくぁwせdrftgyふじこl


 とはいえ、全て再インストールがめんどくせえ必要なものなので、フォルダ名をMSDOS形式にしてみたり、必要ないものは削除してみたり、といろいろやっていたところ、_default.PIFなるものがあることを発見。おや懐かしい「環境変数初期サイズ」なるものを「自動」から「最大値」にしてみたら、あっさり全部入りましたとさ。ふ~~(-∀-メ)

 そしていつものセリフを吐く。  「ゲイツ氏ね」

| | コメント (0) | トラックバック (0)

BREWウガー!!

 というわけで、BREWもやることになったので、カテゴリも新たにスタートなワタクシ。

 つかね。BREW凄いよ。マジで。

 ダメ過ぎて。

 一言で言うと、制約が多いC。
 APIは無理矢理オブジェクト指向風。標準関数壊滅。.bss破棄→グローバル変数/static変数使用不可。メインループ構築不可。スレッドなし。メモリプロテクションなし。エミュレータはIntelバイナリ、実機はARM7バイナリ。

 ウガー!!

 メモリリーク、リソースリークは素のCなのに、C++でラップしようとすると、staticメンバ×。vtbl×。標準ライブラリ×。例外×。STLもちろん×。

 ウガー!!!!

 ようするに「かなり慎重に作らないと、落とし穴多すぎやんけ!」という感じ。う~むむ・・・・。

 2chの関連スレッドでは阿鼻叫喚がw 曰く「BREWアプリはJavaアプリに比べて3倍大変」だとさ。まあ、自分が大変なのはいいんですがね。ごにょごにょ・・・。


 ようするに、C初心者/未経験者にBREWアプリを任せるのはアレでしょうか? ということだ。どーすか?どーなんだ?

| | コメント (0) | トラックバック (0)

中国携帯開発中・・・

 まあノキアたんでやってるんですがね。

 ほとんどMIDPのみで作れという感じ。ケータイのアプリの中では最もプアじゃなかろうか。
 最先端のMIDP2.0搭載機種なら、OpenGL ESまで動くし、JAR領域はメガオーダーだしで、凄いのが作れそうだけど、バリュー帯のシリーズ40だと、MIDP1.0。追加UIも大したこと無い。音楽BEEP単音だしな・・・。

 つーか、N-GAGEも似たようなものなんですけど、
 お前は、これでGBAとかに勝てると本気で思ってたのかと。
 一言で言って、ワンダースワン以下ですた。

 ところで、アテクシはiアプリから入ったわけですが、Dojaの所為で一部勉強しなおしですよ。独自仕様氏ね、という感じ。iアプリは日本語の資料が多いのはいいのだが、ワールドワイドで考えると、au、vodaの方がつぶしが効くのねん。

 むー、それにしても、もうそろそろ英文ドキュメントに慣れんとあかんなー。中国語も覚えなあかんのに・・・ウチュ

| | コメント (0) | トラックバック (0)

Java5.0最強説

オラ、久しぶりにワクワクしたぞ!

というわけでJava5.0ですが。
最強です。
新設された機能はこちらを参照。

 これで、俺的にC/C++から欲しかった機能はプリプロセッサだけになりました。
 元々Javaの構文はC/C++ほど破綻していない(というかC++が破綻しすぎw)ので、新機能でさらにすっきりと書けるようになり、機能面も満足で、かなり理想的な言語になった気がします。
 そろそろアセンブラ/C派だった俺も宗旨変えですかなw マジ、初心者にお勧めの言語になったと思います。

| | コメント (0) | トラックバック (0)

Doja-3.0と3.5(FOMA)との差異

  • HttpConnection#getRequestMethod:"HEAD"メソッドは無くなった。
  • Graphics#drawImage:アフィン変換が可能になった。
  • IApplication#SUSPEND_MULTITASK_APPLICATION:新設。
  • IApplication#LAUNCH_MAIL_RECEIVED:新設。他にもLAUNCH_MAIL_関連も新設多数。
  • IApplication#LAUNCH_MAILMENU:DOPAとFOMAでは動作が異なる。
  • IApplication#launch:動作追加。
  • ImageMapクラス:新設
  • MediaManager#getStreamingImage:新設。
  • Palleteクラス:新設。
  • PalletImageクラス:新設。
  • PhoneSystemクラス#THEME_AV_CALL_IN:新設。
  • PhoneSystem#getSoundTheme:TV電話着信音も更新可能。
  • Spriteクラス:新設。
  • SpriteSetクラス:新設。
  • VisualPresenter#PLAYER_MODE:新設。他にも新設多数。
  • Base64クラス:新設。
  • Phone#call:新設。

| | コメント (0) | トラックバック (0)

iアプリで通信、はじめの一歩(The Fighting!(嘘))

  • iアプリで使えるプロトコルはhttpだけ
  • リクエストラインのメソッドはGET/POST/HEADだけ
  • リクエストヘッダフィールドで使えるのは"Content-Type"と"If-Modified-Since"だけ
  • データの送受信は、HttpConnectonインターフェースで行う。以下は手順
    1. Connector#open()でコネクションを開く(HttpConnection#connect()までは実動しない)。その際のmodeは、POSTの場合、READ_WRITE。それ以外はREADを使う。
    2. setRequestMethod()でメソッドを設定
    3. setRequestProperty()でリクエストヘッダを設定(ex.受け取るデータのタイプをココで設定)。
    4. POSTの場合、OutPutStreamを開き、メッセージボディのデータを出力する。出力完了でclose()。
    5. HttpConnection#connect()で接続。すると、リクエストメッセージ(POSTではデータ込み)がサーバーに送られる。
    6. 必要に応じて、getHeaderField()でレスポンスヘッダフィールドを取得できる
    7. InputStreamを開く、read()でレスポンスメッセージのボディが取得できる。

CGIについてのはじめの知識

CGI プログラムは、実行されると標準出力に出力します。その出力がそのままブラウザに渡されます。 ただし、気を付けるのはまずヘッダを出力し、その後空行が必要なことです。(中略)
引数の取得は、GET の場合は環境変数 QUERY_STRING に代入されています。 POST の場合は標準入力から渡されます。 GET か POST かは 環境変数 REQUEST_METHOD でわかります。また、POST の場合は環境変数CONTENT_LENGTH にデータ長さが入っていますが、 EOF まで STDIN から読み込んでも構わないでしょう。
GET でも POST でも、データは URL エンコードされています。正規表現 [-a-zA-Z0-9_\*] 以外の文字は全て %xx という形 (xx は16進数表記) になって送られてきます。CGI プログラムでは、これを元の形に戻さないといけません。

| | コメント (0) | トラックバック (0)

固定小数点の掟

 iアプリは浮動小数点が使えないので、下駄を履かせて固定小数にして計算します。その際の掟。

  • 整数を掛けたり割ったりする場合は、そのままでOK。
  • 小数同士を掛ける場合は、掛けた後に下駄分を割る。
  • 小数同士を割る場合は、割られる数に予め下駄分を掛けておく。
  • 下駄は2の累乗にしておくと、シフトで賄えるので速いかもしれない。

| | コメント (0) | トラックバック (0)

「+」の恐怖…

 汎用的な簡易オーバーラップウィンドウクラスを作り、その継承クラスとしてメニューリストクラスを作ろうとしていたときのこと。
 あるクラスの継承クラスのclassファイルの大きさは、スーパークラスの大きさに左右されるのかな~、とか思いながらclassファイルを覗くと、割と大きいことに気づき、大きくしている犯人をコメントアウトしながら探っていた。

 犯人は、drawString( "MenuTest"+id, 0, 0, 2, 40 ); とかいう文字列描画メソッドだったのだが、そのあまりの大きさ(300byte近い)に驚いて、色々試行錯誤。

 ふと、+id を.concat( String.valueOf(id) ) に変更すると、67byteも減りますた。

 いや、恐ろしや~、恐ろしや~。わたしがそなたで、そなたがわたし

| | コメント (0) | トラックバック (0)

予期しない例外を丸ごと端末に送る

 アプリに例外が発生した場合、エミュだとコンソールに例外情報が送られますが、実機だとそのままでは送られません。ので、送るようにする方法。
 まず、準備として、以下のことをします。これで最低限端末に例外情報が送られます。


  • ADFのappTraceに"on"と書く(リリース時に外す)
  • 例外時、Exception#toString()を標準出力に出す(System.out.println()等)。printStackTrace()では端末に送られない

 さて、端末でデバッグするときは、全ての”予期せぬ”例外を端末に送って欲しいわけです。なぜなら端末の機種依存で落ちることもあるからです。その瞬間の例外をキャッチできなければ、真実は闇の中です。
 全ての例外を余すことなくcatchするため、独立して動くメソッド(イベントとか)やメインループのメソッドは丸ごとtry/catchで囲みましょう。これでそのメソッドから呼ばれるメソッドで起こる例外は全部catchできるはずです。その後エラー画面を出してあげると親切かもしれません(エラー画面の中でトレース情報を表示できれば、appTraceはいらないかもしれません)。
 次に、try/catch節で囲まなければならない処理を持つメソッドはcatch節の最後でthrowしてしまいましょう。このとき、そのメソッドの宣言にthrowsをつけるのを忘れずに。catchで例外処理をしないのであれば、throws宣言をすれば、try/catchは要りません。
 try/catch節が特に必要ないメソッドはそのままでOKです。例外が発生したら、呼び元に自動的に例外を投げてくれます。

| | コメント (0) | トラックバック (0)

当てにならない備忘録

  • drawImage()より、copyArea()の方が1.7倍速い。
  • 1回の240x240のdrawImage()より、100回の24x24のdrawImage()の方が軽い。
  • 汎用ライブラリを作る場合、メソッドにもフィールド変数にもstaticをつけること。サイズが減る。スコープは影響しないのでお好みで。
  • unlock()が呼ばれたとき、画面に変更があるとpaint()が呼ばれる。
  • 定数定義は#defineを使ったほうが、final staticを使うよりメモリの節約になる。

| | コメント (0) | トラックバック (0)

ぷりぷろぷりぷら

 Javaのクセに機種依存があるiアプリでは、プリプロセッサが欠かせませんが、Javaには標準のプリプロセッサがありません。ナゼ?という感じですが、無いものは仕方ないので、こっちで用意することになります。

 Java用のプリプロセッサで、特にiアプリ開発において有名なものにPPPがあります。
 こいつは、Javaにはないenumキーワードを解釈してくれるおまけ付きで、非常に重宝するのですが、"enum定義に定数定義ができない"、"if 0外しができない"、"#includeが本当にインクルードしてくれるわけではないので、インクルードするファイルにソースを書くことが出来ない"という理由で、惜しまれつつも引退してもらうことになりました。

 enumを使うことが出来ないということを承知すれば(元々無いしね)、C用のプリプロセッサが使えます。BCCでもいいし、VC++でもいいですね。もちろんgccを使ってもOKです。これで、汎用的に使うコードをメソッドとして別ファイルに置くことができます。VC++のclだと、コメントを残したままプリプロセスを行ってくれるので、javadocを通すこともでき、便利です。
 ちなみに、docomoのエミュレータ/ビルド環境を使って、プリプロセスを通すバッチはこんな感じ。

@echo off
REM src2の下にソースを書くと、srcの下にjavac可能なソースができる(VC++版)
cd src2
for %%f in (*.java) do cl /P /EP /C /X %%f
cd ..
del src\*.java
for %%f in (src2\*.i) do move src2\%%~nf.i src\%%~nf.java

 ああ、これでまた一歩、Javaから離れた! ・・・・w

| | コメント (0) | トラックバック (0)

サイズ削減計画の掟

いろんなところを漁って調べたiアプリの主にサイズ削減のための掟をリストしてみる。

  • クラスはIApplicationとCanvasの2つだけ
  • メソッドの数は極力抑える
  • フィールド変数の数を抑える
  • paint()を使わない(Graphicsを取得してlock()/unlock()で)
  • Threadを使わない(start()を呼ぶスレッドのみを使う)
  • Vector/Hashtableを使わない(可変長配列はVectorの方がいい)
  • Timerは使わず、System#currentTimeMillisを使う
  • switchは使わず、if elseを使う(case一個で10byte)。その際、条件が満たされる可能性が高いものから並べると、処理が早くなる。
  • 比較は0と行う。ループはダウンカウントにする
  • Obfuscator必須(あとjargとか)
  • 短いタイミング(描画更新等)でSystem#gcをする
  • Display#setCurrentは起動の一回だけ
  • Stringの"+"は使わない
  • packageは使わない
  • Srting#getBytesを2回以上使う場合、一旦配列に落とすとサイズを食う。しかし、そのまま使うと処理を食うw
  • 変数宣言時にnullを代入しない
  • 文字列の連結は、3回以下ならStringで、それ以上ならStringBufferで
  • Stringを初期化付きで宣言するときは、new String("abc")よりも"abc"で
  • 定数は、-1~5(1) / 8bit整数(2) / 16bit整数(3) / それ以上(7) でサイズが変わる。 long型は0,1以外はサイズが変わらない。
  • フィールド定数(クラススコープの定数)は、インスタンスから導くよりクラスから導くと最適化される。
  • ファイル名は短く。拡張子は無くても構わない。
  • クラスにfinalをつける。
  • インスタンス生成は(メイン)ループの外で行う
  • メソッドのパラメータは先頭3つまでが高速。
  • byte,short型はサイズ縮小の為に使っても意味が無い(配列定数は別?)

参照サイト

| | コメント (0) | トラックバック (0)

アセンブラ気分

 iアプリを作るべく、いろいろなサイトや本を漁り、どうやら敵は「サイズ」であることが判明。503iを無視すればコードサイズ(jar)は30KB以下でなければならない。30KBつったらあーた、240Kbitでっせ。ファミコンのゼビウスも載りません(256KbitROM)。ちなみに1MbitROMは128KBなので、900iでギリギリ足りないサイズ(100KB)。DQ1がやっと載るくらい。もちろんスクラッチパッドという拡張RAMがあるんですが、その代わりJavaなのでどっちもどっちですな。

 で、Javaで(速度ではなく)サイズを気にするなんてのは普通ならしなくていいので、jarサイズを縮めるテクニックなんてのは、常套手段がないわけですが、幾つか見つけまして、とりあえずまとめてみました。

 まず、諸悪の根源はクラスです。クラスを1つ作るとclassファイルが1つ出来、そのサイズが馬鹿にならない(200B程度)ので、クラスは極力減らすことが重要です。クラスの中にクラスを作ったってclassファイルは(innerClass@とかいうプレフィクスのおまけつきで)できてしまうので、無駄なあがきです。
 というわけなので、構造体(としてのクラス)はあきらめましょう。カラーRGBを構造体で纏めるなんてもってのほか(w)です。
 クラスは1つが望ましいのですが、画面描画につかうCanvasと、アプリ起動に使うIApplicationの二つが必要なので、どうしても最低二つにならざるを得ません(画面描画用にPanelを使うのなら別)。
 結論として、iアプリは、IApplicationを継承したアプリ起動クラスとCanvasを継承した画面描画クラスの二つだけで作ることが望ましいです。

 クラスが二つだけということで、すでにオブジェクト指向などというものは役に立たなくなってるわけですが(w)、せっかく二つあるんだから再利用性やクラスの独立性も考えて、二つのクラスにそれぞれふさわしい役割分担をさせたいと思うのがプログラマの人情というものでしょう。
 すぐに考え付くのが、描画周りはCanvas継承クラスで、内部処理やライブラリその他はIApplication継承クラスでメソッドを書くというやり方です。美しいですね。
 しかし、それはお勧めできません。
 別クラスのメソッドを呼び出したり、フィールド変数にアクセスするよりも、自クラスのそれにアクセスした方がサイズ的に有利だからです。
 クラスを増やさないというのはiアプリ鉄の掟ですが、メソッドを増やさないのもまたiアプリの掟です。単なるフィールド変数のアクセサを書くなんてもったいないことをしてはいけないのです。
 そうなると別クラスではpublic宣言をする必要があります。自クラスであればpublicにする必要はありません。
 また、二つのクラスを同じようにメソッドを増やして太らせるよりも、思い切って1つのクラスで全てを行ってしまった方が後々メモリの調整もしやすくて有利です。
 それに片方のクラスを汎用機能を纏め、ライブラリ化してしまうとサイズが固定化/肥大化しがちですし、「動くものは弄るな」の法則が働いてしまいます。

 そうなると、答えは決まってきます。IApplication継承クラスは、Canvas継承クラスのインスタンスを作って、カレントに割り当てるだけで後は何もしない。全ての処理はCanvas継承クラスで行います。アプリケーションの終了でさえ、IApplicationクラスに戻る必要はありません。
 再利用性は、ソースコードのコピペで実現しましょう。どうせiアプリなんて、そう何回もメンテしませんし、Dojaのバージョンが変われば手をつけなければなりません。機種ごとのカスタマイズだってあります。したがってライブラリ化で楽をしようと思わないことが肝要ですw。

 スレッドやイベントは極力使わないようにしましょう。
 paintメソッドは使う必要はありません。Canvas#getGraphicsでGraphicsのインスタンスは取得できます。repaint()で描画指示を出すよりも、lock()/unlock()を使ったほうが制御しやすいし、処理も速いし、機種依存もありません。
 processEventメソッドは使わざるを得ませんが、そこでダラダラキーの処理を行っているとメインループに影響を与えることになるので、typeとparamだけ取得してどっかにコピーして終わらせちゃった方がラクでしょう。
 つまり最低限必要なメソッドは、アプリ起動のIApplication#startとCanvas継承クラスのメインループ(例えばexe())とキー取得イベントをキャッチするCanvas#processEventの3つだけ、ということになります。簡単なアプリなら本当にこれだけでOKです。


 ということで、すでにJavaの体裁を成していない異形のプログラム構造になってしまいましたw。先人たちの業績や今のトレンドをぶちこわしにするプログラミングスタイルですが、どこかなつかしさを感じます。
 これって「昔のゲーム機でアセンブリ言語」で書くときと同じですよね。あるいは8bitPCでBASICプログラミングもそうです。
 スコープなし、構造体なし、オブジェクト指向なし。SFCはそうでした。それでもシムシティが作れてしまうわけです。ウィンドウシステムもお手の物です。別にJavaの機能を駆使しなければ作れないものではないのです。めんどくさいかもしれませんけど、一人で作るくらいのスケールなら、これもアリでしょう。昔とった杵柄気分ですね。

 ただ、ソースファイルまでひとつになってしまうのが難点です。まあプリプロセッサを使えばいいわけですが、そうなると益々Javaではなくなってしまいますな、わははw

| | コメント (0) | トラックバック (0)

Javaとiアプリと私

 iアプリのお仕事をすることになったので、新規カテゴリ設置。

 恥ずかしながら今の今までJava弄ったことないです。そのくせCは16年くらいどっぷりなもんで、ついついC的思考でJavaを見てしまいます。しかも、iアプリ。JavaはJavaでも組み込みJavaなので、「クラスの数は極力抑えて、ひとつのクラスを万能化させようね」な世界です。オブジェクト指向って何?Javaにする意味あるん?

 てな感じで、中途半端なJavaプログラマになりそうな予感バリバリですが、Javaに関する役に立たないアレコレを書き殴っていこうかなと思います。

 ブログなので、Javaとかiアプリとかのキーワードで検索に引っかかる可能性大ですが、来ても役に立たないどころか、バリバリJavaプログラマの方には「うっきー!」となるかも知れません。予め謝っておきます。すまん。
 

| | コメント (0) | トラックバック (0)