撰寫PalmOS上的Spotlet時,我們可以利用System.out.println()函式幫我們印出一些訊息以幫助除錯,那麼在手機上的MIDlet呢? 原則上,我們還是可以利用System.out.println()函式做一些輸出。當仿真器執行時,就會在命令列上輸出一些訊息。
另外,在PalmOS上,有KVMutil.prc可以幫助我們紀錄程序所輸出的訊息。那手機上呢? 因為沒有實際的機器可以測試,因此這個問題到現在還不得而知,相信Motorola到時候會有完善的解決方案吧!
在Motorola J2ME SDK內附的說明文件之中,概略地提到了除錯的問題,裡頭提到,往後如果我們要進行上機除錯(on-device debugging)的話,必須要滿足幾個條件:
1. 機器本身要具備除錯相關功能,並與KDWP(Kvm Debug Wire Protocol)兼容。因為除錯時,除錯工具需要利用KDWP和機器上交談以取得除錯信息。
2. 制造廠商本身要提供下載MIDlet到手機上以進行除錯的方法。
3. 提供對MIDlet除錯的工具,必須支持手機在利用KDWP除錯時所此用的傳輸媒介(例如序列阜或UDP)。
除錯方式有解,MIDlet程序的撰寫應該是很方便的事情了。
Motorola J2ME SDK對中文的支持
相信看過RUN!PC 11月號的文章「利用Java 撰寫PalmOS應用程序基礎篇」的讀者,在撰寫PalmOS上的Spotlet時一定會遇到中文無法正常顯示的問題。中文的問題分成兩個部分,一個是在使用者接口上的中文問題,一個是在命令列輸出(利用System.out.println()函式所做的輸出)上的中文問題,請大家做個小實驗,將前面我們所撰寫的程序改如下:
HelloMIDlet.Java
import Javax.microedition.lcdui.*;
import Javax.microedition.midlet.*;public class HelloMIDlet extends MIDlet
{
private Display firstDisplay ;
private Form firstForm ;
HelloMIDlet()
{
firstDisplay = Display.getDisplay(this) ;
firstForm = new Form("哈啰!MIDlet") ;
StringItem firstStrItem = new StringItem("哈啰","米德列特") ;
firstForm.append(firstStrItem) ;
System.out.println("MIDlet激活") ;
}protected void startApp() throws MIDletStateChangeException
{
firstDisplay.setCurrent(firstForm) ;
}protected void pauseApp()
{
}protected void destroyApp(boolean unconditional)
throws MIDletStateChangeException
{
}
}
將本MIDlet編譯並經過預身審核之後,我們開啟仿真器來執行此MIDlet,底下為執行結果:
使用者接口輸出
命令列輸出
我們從結果發現,預設的編譯指令會讓使用者接口正常輸出中文,而命令列無法輸出正確的中文。
接著請將compileAll.bat之中原本的指令:Javac -O -bootclasspath ..\..\lib %COMPILECLASS%
修改為:Javac -encoding ISO8859_1 -O -bootclasspath ..\..\lib %COMPILECLASS%
之後,重新編譯此MIDlet執行結果:
使用者接口輸出
命令列輸出
我們從結果發現,預設的編譯指令會讓使用者接口無法正常輸出中文,而命令列卻可以輸出正確的中文。
這個結果與PalmOS上所做的中文測試結果有所不同。
當您撰寫Spotlet時,如果您使用 javac 。。。指令時,您會發現仿真器上的使用者接口輸出是亂碼,可是命令列上的輸出卻可以正常輸出中文。但是如果您使用的是Javac -encoding ISO8859_1 。。。指令,則CLDC內附仿真器上的使用者接口輸出或是命令列上的輸出全部都變成亂碼,無法正常輸出中文(這個部分是因為CLDC內附仿真器實做的問題,造成與實際機器的結果有差)。
總之,如果之前您所撰寫的Spotlet無法在裝有中文系統的實體機器或POSE上正常輸出中文,請您也如法炮制,在編譯指令中加入 -encoding ISO8859_1 ,就可以在實體機器或POSE上看到正常的中文字了。
會產生此問題的主因,主要是因為編譯好的Java類別檔(byte code)之中,所有的文字編碼都采用UTF8。舉例來說,當您在程序代碼裡用到"激活"這兩個中文字時,
"起"這個字的Big5編碼為B1D2。
"動"這個字的Big5編碼為B0CA。
我們會使用javac xxxx.java來編譯原始碼以產生類別檔。其實這行指令,在繁體中文的Windows環境底下,相當於javac -encoding "Big5" xxxx.Java。也就是說,當編譯器讀取到Big5編碼范圍的中文字時,會自動將此Big5碼經過「Big5 e Unicode 對照表」將Big5轉為Unicode,也就是說,經過查表之後,
"起"這個字的Unicode編碼為555F。
"動"這個字的Unicode編碼為5272。
然後再利用UTF8編碼將此Unicode轉為UTF8,儲存在類別檔之中,因此,如果您用UltraEdit之類的文字編輯器查看類別文件時,您會看到,
"起"這個字的UTF8編碼為E5959F。
"動"這個字的UTF8編碼為E58B95。
接著,當我們在程序執行時如果要將中文輸出,則JVM會負責讀進UTF8碼,然後將其轉回Unicode,最後依據您所使用的作業環境預設的編碼轉回Big5,再輸出至屏幕上。
可是經過測試結果,KVM似乎只有做到把UTF8讀進來,轉換回Unicode之後就直接輸出了。少了轉回Big5的步驟,因此,操作系統把Unicode當作Big5來處理,自然就找不到該碼所對應的中文字了,也因此輸出的是一堆 ????? 的符號。這也是我們在PalmOS上即使裝了中文系統,也無法正常顯示中文的緣故。
OK,既然知道KVM只幫我們做了一半的工作,那事情就好辦了,我們只要讓UTF8轉回之後,仍然保有Big5的編碼方式即可,於使我們使用指令 javac -encoding ISO8859_1 xxxx.Java,請編譯器不要將程序代碼中中文Big5編碼的兩個byte視為一體(因為視為一體就會引發查詢Big5 --> Unicode對照表的工作),只要將中文當作是普通的西歐字母字集即可,因此,當我們使用了上述指令,您會發現類別檔之中的中文變成,
"起"這個字的UTF8編碼為C2B1 C392。
"動"這個字的UTF8編碼為C2B0 C38A。
大家可以發現編譯器把B1、D2、B0、CA個別當作一個碼來處理。於是,當KVM讀到此編碼時,就會將他們轉回B1D2以及B0CA,然後KVM直接輸出,就可以正常地使用中文了。
最後總結整個問題,就筆者的推斷,CLDC內附的仿真器再沒有使用 javac -encoding ISO8859_1 xxxx.Java 指令之前,會在使用者接口會是命令列輸出亂碼,這才是正常的結果, 而Motorola J2ME SDK內附仿真器的使用者接口中文之所以沒問題,很可能只是因為仿真器在實做的差異。因此以KVM的輸出結果來看,很可能在實際的手機上,我們都必須加上 -encoding ISO8859_1 選項才能正確輸出中文吧!
在此特別感謝靜宜大學資管系的唐恺隆([email protected])同學。因為筆者與他經過熱烈的討論之後,我們才能對J2ME的中文問題有更深入的認識。
援Motorola J2ME SDK的開發工具
撰寫本文的時候,支持MIDlet開發的整合環境(IDE)只有Motorola J2ME SDK內附文件之中所提到的CodeWarrior而已。相信其它廠商,如Borland,應該也會很快地利用其產品JBuilder的OpenTools API來支持MIDlet的開發才對,更何況Borland JBuilder目前已經有Spotlet的解決方案了。
因為筆者無法拿到CodeWarrior作測試,所以無法在此提供大家相關信息,相信如果有機會的話,會另外以專文向大家介紹如何利用CodeWarrior撰寫MIDlet。
Motorola J2ME SDK內附文件在附錄的部分有對利用CodeWarrior開發MIDlet做簡單的介紹,相信對初學者來說,已經相當足夠了。
Motorola J2ME SDK內含的輔助開發工具
在Motorola J2ME SDK之中內含三項輔助開發工具,可以便利我們的程序開發工作,它們分別是:
J2ME仿真器(J2ME Emulator)
讓您可以在您的PC上仿真Motorola將來會支持J2ME的手機裝置。如此一來就可以在PC上直接測試寫好的程序。
Bytecode驗證器(Bytecode VerifIEr)
此驗證器用來驗證類別檔(classfile)之中的bytecode不會對內存做非法的存取。並確認加載虛擬機器的類別文件所做的所有動作皆符合Java虛擬機器規格(Java Virtual Machine Specification)。
組態編輯器(Configuration Editor)
讓您能夠建立或修改device profile。 在Motorola J2ME SDK內附的文件之中對這三個工具有詳細的說明,筆者在此就不再贅述了。
總結
呼!好累人,終於到了該做總結的時候了! 大家以為MIDlet就這樣結束了嗎?不! MIDlet還有許多好玩的玩意兒呢! 我們將在本系列之後的文章中為大家更深入探討MIDlet。咱們下次見。
附錄:范例程序
Motorola J2ME SDK之中內附許多有趣的范例,它們位於demo/midlets/目錄底下。有興趣繼續精進的讀者可以藉由這些范例學到更多有關MIDlet的深入技巧,由於這些范例的執行畫面過大,所以在本文之中就將他們省略,請讀者們自行參考說明文件。這些范例程序有:
Bounce
com.mot.J2ME.midlets.bounce.BouncePaddleBall
com.mot.J2ME.midlets.paddleball.PaddleBallScribble
com.mot.J2ME.midlets.scribble.ScribbleFontDemo
com.mot.J2ME.midlets.tutorials.FontDemoGraphicsDemo
com.mot.J2ME.midlets.tutorials.GraphicsDemoRecordStoreDemo
com.mot.J2ME.midlets.tutorials.RecordStoreDemoUDP Tutorial Application
com.mot.J2ME.midlets.tutorials.UDPReceiveAlertTest
com.mot.J2ME.midlets.tests.AlertTest
ChoiceGroupTest
com.mot.J2ME.midlets.tests.ChoiceGroupTestDateFIEldTest
com.mot.J2ME.midlets.tests.DateFIEldTestFormTest
com.mot.J2ME.midlets.tests.FormTestGaugeTest
com.mot.J2ME.midlets.tests.GaugeTestKeyEventsTest
com.mot.J2ME.midlets.tests.KeyEventsTestTextBoxTest
com.mot.J2ME.midlets.tests.TextBoxTestTextFIEldTest
com.mot.J2ME.midlets.tests.TextFIEldTestTickerTest
com.mot.J2ME.midlets.tests.TickerTest
網上資源
網站:Motorola官方網站http://www.motorola.com/Java/
Metrowerks(CodeWarrior) http://www.Metrowerks.com
Trackback: http://tb.blog.csdn.Net/TrackBack.ASPx?PostId=562445