アットマーク・アイティ @IT@IT情報マネジメント@IT自分戦略研究所QA@ITイベントカレンダー  
 @IT > Master of IP Network > Mobile Connection > 互換性のあるiアプリ作成法
 

DoJaによるiアプリの開発入門(6)
互換性のあるiアプリ作成法

服部隆志
http://www.sinsen.org/
http://www.ngy1.1st.ne.jp/~takashi/sinsen_index.html
2001/8/3

 

今回のおもな内容
各端末が持つハードウェアの特徴
色数
画面サイズ
フォントサイズ
ボタン形状
バーチャルマシン実装上の機種依存
Panel上のGUI表示
Panelの切り替えとフォーカス
Canvas#repaint()のタイミング
リソースの扱い
PhoneSystemの連続実行
音の停止と再生
最小時間の計測
バグ、バグの疑いのある機種依存
N503iのGETを使ったCGI連携
P503iの4月問題
SO503iのバージョンアップによるSPsizeの拡大禁止
次回はファイルサイズの縮小

 本来であれば、Java言語で作られたプログラムは同じ仕様のすべてのプラットフォームで同じように動作することが期待されます。しかし、実際には、これまでの連載で紹介してきたサンプルのiアプリにも、機種によって問題の発生する可能性があるものがありました。これらの原因は、1つのプラットフォーム上で動作するJava実行環境を端末メーカーごとに開発しているためで、同じ仕様をもとにしたとしても実装上の違いが出てしまうからです。

 J-フォンやKDDIでは、この問題に対処するため、端末で使用するJava実行環境を統一しています*1。DoJaでもこのような環境が整えばいいのですが、すでに発売されている503iシリーズでは無理なので、それらの違いにどう対処するかが、iアプリを作るにあたっての大きな問題となります。

 今回は、現在発売されている503iシリーズで、問題となる主な機種依存個所とその対応策を知り、互換性のあるiアプリを作成する方法を紹介します。

*1 J-フォンもKDDIも、ともにアプリックスの開発した「microJblend」という組み込み向けのJavaソリューションを搭載することを表明している。
http://www.aplix.co.jp/pressroom/press-release/PR010409.html
http://www.j-phone-east.com/company/n/2001/010417b.htm
http://www.kddi.com/release/2001/0625/

  各端末が持つハードアウェアの特徴

 現在発売されているすべてのiアプリ対応携帯端末で動作するiアプリを作るには、各端末の特徴を知り、それによって制限される部分を明確にする必要があります。

 例えば、SO503iでは操作ボタンの上下がジョグダイヤルになっているので、操作キーのオン・オフ状態が非常に短い時間に連続して実行され、またボタンの押しっぱなしという状態の判定ができません。このためSO503iと互換性を保つ場合は、操作ボタンのほかに数字キーでも操作できるようにした方がよい場合があります。

 表1に各端末の持つ特徴を示します。で表示されている部分が、互換性を保つときに注意すべき個所です。プログラムを作成する前に、これらの個所への対策を考えたり、これらの個所を最低スペックとした設計をする必要があります。なお表1中の「microedition.platform」は、System#getProperty("microedition.platform")を実行すると入手できる値で、これにより機種の判別をして機種限定のプログラムを実行させることができます。

端末名 P503i P503iS F503i N503i SO503i D503i
色数 256 256 256 4096 65536 4096
画面サイズ 120×130 120×130 120×130 120×130 120×120 132×126
標準フォントサイズ 12×12 12×12 12×12 12×12 14×14 16×16
操作ボタン形状 スティック スティック ボタン ボタン ジョグダイヤル ボタン
ヒープメモリサイズ(Kbytes) 256 256 600 98 342 110
micro
edition
.platform
Panasonic P503i Panasonic P503iS f50x pdc SO503i D503i
表1 503iシリーズの各端末の特徴

 さて、それでは、それぞれの特徴について詳しくみていくことにします。

色数

 P503i(S)、F503iでは固定の256色しか表示することができません。これにより本来表示させたい色が近似されて思いどおりの色で発色されないことがあります。特にグラデーションを表示させたい場合や、Canvas#getColorOfRGB(int,int,int)で色を指定したい場合には注意が必要です。違う色を指定しているはずが、実機では同じ色だったということがあります。

あらかじめ近似されるしきい値を確認し、同じ色にならないように指定します。以下の表がP503i(S)、F503iでのしきい値になります。RGB332と呼ばれ、赤(Red)と緑(Green)に8段階(3bit)、青(Blue)に4段階(2bit)で、8×8×4=256色となります。

P503i(S)
Red 0-18 19-54 55-91 92-127 128-164 165-200 201-237 238-255
Green 0-18 19-54 55-91 92-127 128-164 165-200 201-237 238-255
Blue 0-42 43-127 128-212 213-255
F503i
Red 0-31 32-63 64-95 96-127 128-159 160-191 192-223 224-255
Green 0-31 32-63 64-95 96-127 128-159 160-191 192-223 224-255
Blue 0-63 64-127 128-191 192-255
表2 P503i(S)とF503iのしきい値

●画面サイズ

 SO503iでは正方形、D503iでは横長という特徴があります(そのほかの機種は縦長です)。縦120ドット以上で画像や文字を表示すると、SO503iでは欠けたり表示されなかったりします。またD503iでは横のサイズが異なるため、画像や文字が思った位置に表示されなかったり、画面の縁に空白が残ったりします。

最小画面サイズであるSO503iの120×120に収まるようにします。また、唯一横幅の違うD503iでも左右の位置を合わせるための工夫が必要となります。

public void paint(Graphics g){
  int width = getWidth(), height = getHeight();
  g.drawImage(image, width/2 - image.getWidth()/2 , height/2 - image.getHeight()/2 );
}
リスト1 すべての機種で画像を中央に表示

注意:Graphics#setOrigin(int x,int y)で描画原点の設定ができますが、P503i(S)で使用した場合に無関係な部分にまでその範囲が設定されることがあるため、リスト1のようにして計算する必要があります。

●フォントサイズ

 SO503iとD503iは、標準で使用するフォントサイズが異なります。そのため、文字を並べて表示すると、文字が重なることがあります。

SO503i、D503i共にフォントとして「SMALLサイズ」を指定すると、ほかの機種と同じサイズのフォントを表示することができます。

public void paint(Graphics g){
  int width = getWidth(), height = getHeight();
  Font font;

// もしSO503i、D503iだったらSMALLを指定
  String platform = System.getProperty("microedition.platform");
  if(platform.equals("SO503i")||platform.equals("D503i")){
    font = Font.getFont(Font.FACE_SYSTEM | Font.STYLE_PLAIN | Font.SIZE_SMALL );
  }else{
    font = Font.getDefaultFont();
}

  String str = "draw string";
  g.drawString(str , width/2 - font.stringWidth(str)/2 , height/2 - font.getHeight()/2);
}
リスト2 すべての機種で文字を中央に表示

●ボタン形状

 SO503iではボタンの上下にジョグダイヤルが使われています。ジョグダイヤルによる操作ではボタンのオン・オフが一瞬のうちに終わってしまうため、上下ボタンの押しっぱなしができないだけでなく、プログラムのメインループでボタンの状態を入手している場合は取りこぼす可能性があります。

 またP503i(S)ではスティックになっており、上下左右のうち1カ所だけが押された状態しか入手することができず、ボタンの同時押しが判定できません。同様にN503i、D503iでも一部のボタンの同時押しの判定ができなくなっています。

ボタンの押しっぱなし、ボタンの同時押しが必要なプログラムでは、数字キーによる入力をボタンのように受け付けるようにします。

int key = getKeypadState();

if( ((key&(1<<Display.KEY_UP))!=0) || ((key&(1<<Display.KEY_8))!=0) ){
……
}
リスト3 ボタンの上、あるいは数字キーの8が押された場合の処理

図1 左からP503i、SO503i、F503iのボタン形状

●ヒープメモリサイズ

 互換性を考える場合に優秀な成績を持つN503iが唯一問題とするのが、このヒープメモリのサイズです。大きな配列や多くのリソースを扱う場合は注意が必要です。

 ただし、リソースに関してはリソース管理のプログラムが優秀であることからそれほど苦にすることはありません。むしろリソースの管理が特殊なSO503iの方に、注意が必要な場合があります。

できるだけ大きな配列やリソースを扱わないようにします。例えば、使用する数値範囲が小さな値に限られている配列では、安易にint(32bit)の配列を作らず、それ以下のサイズ(byteやshort)の配列を用意することでメモリを節約します。ほかに、使わなくなったリソースを開放したり、ガーベジコレクションを強制的に動作させることでメモリを空けることができます。

  バーチャルマシン実装上の機種依存

 次に、実装されているバーチャルマシンによる違いを説明します。

●Panel上のGUI表示

 DoJaでは、標準でのGUIの表示位置、方法などは機種依存になっています。これにより、機種が違うことで思ったように表示されていないことがあります。

アプリケーション設計の段階でコンポーネントの配置順番を変更することや、Panel#setLayoutManager(LayoutManager)にnullを設定して各コンポーネントの場所、サイズを指定することが挙げられますが、ハードウェアに依存する部分が多いため、それでも完全な互換性を実現することは難しくなっています。

●Panelの切り替えとフォーカス

 N503iなどでは、ほかのフレームからキー操作のKeyPressedイベントに反応してPanelに切り替えたとき、Panel上のGUIにKeyReleasedイベントが渡されてしまう場合があります。これにより意図しない場面でGUIが選択されてしまいます。

Panelの切り替えにキー操作を利用する場合は、KeyPressedイベントではなく、KeyReleasedイベントを利用することで解決できます。

●Canvas#repaint()のタイミング

 機種によって、新たに再描画用スレッドを作成するタイプ(F503i、SO503i、D503i)と、repaint()内部で直接paint(Graphics)が実行されるタイプ(P503i(S)、N503i)の2つに分かれます。新たなスレッドが作成される場合は、前の描画と処理が重なる可能性があり、その場合に前の処理が中止されたり、プログラムによっては例外エラーが発生することがあります。特に中止される場合には、必要な描画まで中止されてしまうことがあるので注意が必要です。

Canvas#getGraphics()を使って実画面のインスタンスを入手し、それをCanvas#paint(Graphics)に直接渡してやることで別スレッドを利用することなく再描画することができます。

// これまで使っていたrepaint()をコメントアウトする
// repaint();

// 現在のスレッドを使って再描画を実行する
paint( getGraphics() );

リスト4 repaint()をpaint(getGraphics())に変更する

 ほかに、Canvas#getGraphics()で実画面のインスタンスを入手したら、それを使って直接描画処理を実行する方法があります。実際の画面に反映されるタイミングはCanvas#lock()Canvas#unlock(boolean)を使って調節できます。この方法では、paint(Graphics)を一切使うことなく描画することができます(Canvas#paint(Graphics)はabstructなので実装する必要はあります)。

Graphics g = getGraphics();

g.lock();

// 描画処理
g.clearRect(0,0,getWidth(),getHeight());
g.drawImage(image,x,y);

// 実際の画面に結果を反映
g.unlock(false);
リスト5 paint(Graphics)以外で描画する

●リソースの扱い

 SO503iではMediaResourceの扱いがほかの機種と異なり、意図的にリソースの破棄をしないとメモリ上に存在し続けます。これによりメモリが使われて足りなくなることがあります。大きな画像を何十個も扱う場合や、ネットワークなどから更新される画像を次々に生成する場合などは注意が必要です。

大きな画像を複数扱うのはできるだけ避け、画像を更新する場合などは適切な処理をしてリソースを破棄します。

image.dispose();
mediaImage.unuse();
mediaImage.dispose();
リスト6 イメージの破棄

●PhoneSystemの連続実行

 P503i(S)やSO503iでは、PhoneSystemによるハードウェアへのアクセスを短時間に連続して実行すると動作が不安定になったり強制終了されることがあります。また、P503i(S)でバイブレータの設定と音の再生を同時に行うと、どちらか一方しか実行されないことがあります。

PhoneSystemを連続して実行させたい場合にもスレッドなどを使い、間を取ることである程度改善されます。バイブレータと音の再生との同時実行は機種依存にするか、タイミングをずらして交互に実行させるなどの対策が必要になります。

●音の停止と再生

 音の再生中に停止させ、すぐに別の音を再生しようとすると、多くの機種で正常に再生が行われません。P503i(S)の場合は次の再生が処理されず、N503iとSO503iの場合は例外(エラー)が発生することがあります。

MediaListenerを使い、音の途中停止(AudioPresenter#AUDIO_STOPPED)を確認した後で、あらためて次の音の再生を行います。あるいは一定時間(約100〜300ms)おいてから次の音の再生を行います。

●最小時間の計測

 DoJaで時間を計測する手段としては、System#currentTimeMillis()を利用する場合と、ShortTimerなどのタイマを利用する場合の2つがあります。しかし、N503iではSystem.currentTimeMillis()の精度が100ms単位までしか使えません。ShortTimerではF503iとSO503iで100ms単位の精度しかありません。つまり互換性を保ちつつ計測できる最小時間の単位は100msまでということになります。

計測するルーチンなどを各端末で100ms以上となるようにすることが挙げられます。何千回、何万回とループさせることで100msの精度でも計測することができるようになります。

  バグ、もしくはバグの疑いのある機種依存

 バグ、もしくはバグとして公表されているものではありませんが、実際の運用上でバグではないかと思われるものについての対応策を紹介します。

●N503iのGETを使ったCGI連携

 DoJaの仕様では、ネットワークにはシフトJISを使うことが決められていますが、N503iではGETを使ったCGIへのデータ送信時にのみ正しくエンコードされないため、CGI側でデータを入手できないことがあります。

com.nttdocomo.net.URLEncoder#encode(String)を使い、送信データをエンコードしてやることでほかの機種と同じ処理ができるようになります。

String url = IApplication.getCurrentApp().getSourceURL() + "test.cgi?" + URLEncoder.encode(sendData);
リスト7 URLEncoderの使い方

●P503iの4月問題

 P503iではJAMに4月を「Apr」と書いた場合にエラーが発生することが確認されています(http://www.nttdocomo.co.jp/i/java/caution.html)。

4月の明記を避け、3月「Mar」や5月「May」を使うことで、ほかの端末との互換性が保たれます。

●SO503iのバージョンアップによるSPsizeの拡大禁止

 「HTTP通信とスクラッチパッドへのアクセス」でも書きましたが、SO503iでiアプリのバージョンアップをする場合、スクラッチパッドに割り当てるサイズを以前より多くすることで他のアプリケーションのデータを破壊してしまうことがあります。

 この問題に対しては、現在ドコモショップにて修正機との交換が開始されています。セキュリティ的な問題もあるので、以前からのSO503iユーザーは必ず交換してください。詳しくは「DoCoMo by Sony SO503i 」をご愛用のお客様へ(お知らせ)をご覧ください。

一応、対応策としては、あらかじめ大きなSPsizeを設定しておく、バージョンアップ時のSPsize設定を変更しないといった方法があります。

  次回はファイルサイズ縮小

 今回は互換性を保つために注意すべき機種依存とその対策法を紹介しました。次回は、JARで10Kbytesというサイズ制限の中に、よりたくさんの内容を詰め込むためのファイルサイズ縮小方法についてご紹介したいと思います。

 次回、「ファイルサイズ縮小方法」編の掲載は8月下旬ごろを予定しています

「連載 DoJaによるiアプリの開発入門」


 


 
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

   
@ITトップMobile Connectionフォーラム トップ会議室利用規約プライバシーポリシーサイトマップ