[轉帖]J2ME學習札記1

shenvon36發表於2002-08-09
J2ME就是Java 2 Platform,micro Edition的縮寫。J2ME是Java 2的一個組成部分,與J2
SE、J2EE並稱。根據Sun Microsystems,Inc.的定義:J2ME是一種高度最佳化的Java執行環境,針
對市面上的大量消費類電子裝置,例如Papers、cellular phones(蜂窩電話), screen-phone
s(可視電話?)、digital set-top boxes(數字機頂盒)、car navigation systems(汽車導航
系統)等等。
J2ME技術在1999年的JavaOne Developer Conference大會上推出。J2ME技術將Java語言
的與平臺無關的特性移植到小型電子裝置上,允許移動無線裝置之間共享應用程
為了學習J2ME技術,我需要安裝什麼樣的軟體?
1)、J2ME Wireless Toolkit
J2ME Wireless Toolkit簡稱J2MEWTK,目前最新的版本就是1.0.3 Beta,J2MEWTK有什麼用?打
一個比方,J2MEWTK之於J2ME程式的開發,就相當於JDK之於Java程式的開發。J2MEWTK是由Sun
公司開發的,你可以到Sun的網站去下載,這個工具和JDK一樣,是完全免費的。

2)、J2SE SDK 1.3
J2SE SDK 1.3亦即JDK 1.3,JDK有什麼用?相信學過Java語言的人都知道,我就不多寫了,在安
裝J2MEWTK之前,你必須確保你的系統已經安裝了一個可用的JDK。建議不要使用JDK 1.2和JD
K 1.4,前者版本低,後者不穩定。

3)、Tomcat 3.2.3/4.0
Tomcat 3.2/4.0用作伺服器軟體,為J2ME手機提供服務。由於手機的資源有限,所以我們需要
儘量將商業計算集中於伺服器端完成,減小客戶端的負擔,所以要開發J2ME程式,一個伺服器軟
件是少不了的。我採用JSP作為伺服器端的解決技術,所以我選用的Web伺服器是Tomcat。但是
你也可以選用IIS+ASP、Apache+PHP。這個選擇不是唯一的。


第一步,安裝JDK 1.3.0或者安裝一個包含JDK 1.3.0的軟體。我安裝了Jbuilder 5.0,它所帶
的JDK是HotSpot 1.3.0_01 Client版。

第二步,安裝J2MEWTK 1.0.3 Beta,在安裝的過程中,需要選擇系統中JDK的安裝目錄,安裝程式
一般可以自動查出來JDK的安裝目錄,我們不用操心。

第三步,安裝Tomcat 3.2.3/4.0,Tomcat 3.2.3是最穩定的3.x系列,推薦使用。Tomcat 4.0剛
剛釋出了正式版,也不妨一試。Tomcat 3.2.3/4.0需要經過配置,才能夠執行。

第四步,測試Tomcat是否能夠正常執行JSP程式。這一步很重要。

J2ME開發工具比較:
1)、J2MEWTK,這個工具在前文已經提到過,它是最基本的J2ME程式開發工具,免費,體積小,速
度較快,完全遵守J2ME的各種規範。具有簡單的IDE介面,易於上手,開發十分方便快捷,可以和
Forte 3.0捆綁。J2MEWTK適用於初學者和已經達到很高水平的開發者。竊以為J2MEWTK+JDK+
Editplus/UltraEdit是絕配。評語:重劍無鋒,大巧不工。

2)、VisualAge Micro Edition 1.4。這是IBM的產品,號稱是J2ME開發領域的TOP 1,但是我用
了半天,也沒有看出好在那裡。馬上就刪除了。視窗太複雜,不明所以,開發起來很難適應,速
度和J2MEWTK一樣,比較龐大,裝了這個東西,你的C盤就要小心了,多了很多亂七八糟的檔案,還
註冊了許多COM元件,典型的非綠色軟體。評語:!#$#%$#$%$#%@$@#。

3)、CodeWarrior for Java 6.0。這是Motolola的產品,功能十分強大,整合度很好,開發,調
試,釋出J2ME程式都很方便(還可以做一般的Java Program)。它的IDE和Visual Studio十分相
似,很容易上手。CodeWarrior比較適合中等水平的開發者的使用。不過CodeWarrior不是免費
軟體,你只能夠免費使用30天。評語:摩托羅拉CodeWarrior,隨時隨地J2ME。

4)、Borland Jbuilder 5.0的Nokia Bobile版。沒用過。評語:缺。

在開發J2ME應用程式之前,我們必須選擇這些程式執行的平臺,亦即開發出來的J2ME程式
執行在那一種手機或者是移動裝置上面。在開發的過程中,我們需要對J2ME應用程式進行測試
,當然了,自己擁有一款支援J2ME的手機是最好的,例如Motolola的i85s,但是這個要求不是每
一個開發者都能夠滿足(我連手錶都沒有,更不用說手機了),因此,大多數的J2ME開發環境都提
供了各種各樣的手機、移動裝置模擬器,你可以首先在手機模擬器上測試你的J2ME程式,開發
完畢以後,再將程式交給專業的廠商(一般是移動裝置提供商),由它們將程式載入手機中進行
真實的程式測試。模擬器和真實的裝置之間有一定的差別,但是你的程式只要在模擬器上透過
了,那麼問題不會很大。
J2MEWTK提供六種模擬器,分別是:Default Color Phone、Default Gray Phone、Minimu
m Phone、Motolola i85s、PalmOS Device、RIM Java Handle。這些模擬器雖然外觀不一樣
,操作也不太一樣,但是J2ME程式在其上執行的結果是不會有什麼區別的,在真實的裝置上也是
沒有什麼區別的,這體現了Java的跨平臺特性。你還可以自定義自己的手機模擬器,這在J2ME
WTK的User Guide中有詳細的描述。
在開發過程中,選擇何種模擬器是十分重要的,原則上來說,你為那一種裝置開發程式
,就要使用那一種裝置的模擬器。但是J2ME程式在不同的模擬器上的執行效果基本上是一致
,所以你也可以採用你自己喜歡的模擬器。我們推薦你選用RIM Java Handle模擬器作為開發
的首選模擬器,因為它的螢幕很大,看起來很舒服(但是別忘了你的真實裝置的螢幕大小)。
在J2MEWTK中,可以設定預設的模擬器,怎麼設呢?從開始選單選擇J2MEWTK---->Default
Device Selection,在下拉選單框中選擇模擬器的名字,然後單擊OK按鈕即可,J2MEWTK就會把
這種模擬器認為是預設的模擬器。你也可以在開發環境中每次手動選擇模擬器,不過這樣做顯
然比較麻煩。J2MEWTK在初始情況下,預設的模擬器是Default Color Phone,說實在話,我從
來沒有看見過這麼難看的手機。

現在開始嘗試開發J2ME程式。我的選擇是Windows XP 2600 Professional+J2SE SDK 1.3.
0+Tomcat 4.0+J2MEWTK 1.0.3Beta。從開始選單中選擇J2MEWTK---->Ktoolbar。Ktoolbar是
J2MEWTK提供的一個簡陋的IDE工具。
進入Ktoolbar以後,觀察視窗,在選單的下面有四個按鈕,分別是:
New Project:建立一個新的專案。
Open Project:開啟一個專案。
Setting:對當前專案的環境進行設定。
Build:編譯專案中的所有Java檔案。
Run:啟動預設的模擬器,將當前專案載入,執行。
Clear Console:清除控制檯輸出。
在上述按鈕的下面,有一個下拉選單框,在這裡你可以設定當前專案所使用的模擬器,這個
設定可以覆蓋預設的模擬器。在此下拉選單框下面,是一個文字框,這就是所謂的控制檯了。
所有編譯、執行資訊都會在這個控制檯中輸出。你可以使用Clear Console按鈕將控制檯中的
資訊完全清除。
現在來看看選單。Ktoolbar的選單極其簡單,沒有什麼可說的。Project選單的package選單
項的作用是將當前專案打包輸出。這個選單項特別有用,當你完成專案開發之後,使用這個菜
單項可以產生一個jar檔案,這樣就完成的專案的初步釋出。
現在來建立一個新的專案,單擊New Project按鈕,或者是使用File選單的同名選單項。出現
一個新視窗。這個新視窗有兩個文字框,第一個文字框是Project Name,輸入fancy。第二個文
本框是MIDlet Class Name,輸入fancy.test.HelloWorld。然後單擊OK,又出現一個對話方塊,要
你配置專案的環境,不理,單擊OK按鈕關閉該視窗,回到Ktoolbar的主視窗。經過上述步驟,你
已經建立了一個名為fancy的J2ME專案。

安裝J2MEWTK以後,你應該仔細瀏覽一下J2MEWTK的目錄結構,這是一個很好的習慣。J2MEWT
K的目錄結構如下:
appdb資料夾:裡面有duke的一些靚照。
apps資料夾:裡面有J2MEWTK的一些例子程式,我們建立的專案檔案也存放在裡面。
bin資料夾:裡面全部是exe程式。
docs資料夾:不用多說了,是地球人都知道。
lib資料夾:存放MIDP API。
wtklib資料夾:存放J2MEWTK用到的類庫,以及一些資原始檔,比如按鈕的圖示等等。
在這些資料夾中,apps資料夾特別需要留意,這個資料夾有下列子資料夾:
example:存放J2MEWTK的例子,側重於圖形方面,例子比較大,複雜,難看懂。
lib:空,不知道放什麼東西。
tmplib:空,不知道放什麼東西。
UIDemo:存放J2MEWTK的例子,側重於使用者介面設計方面。例子不大,難度中等。
fancy:這個資料夾原來是沒有的,當我們建立fancy專案的時候,J2MEWTK自動為我們建立的文
件夾。
進入fancy資料夾,它裡面又有很多子資料夾,如下所示:
bin:存放專案的打包輸出檔案。
classes:存放編譯器產生的class檔案。
lib:空,不知道有什麼用。
res:存放資原始檔,例如專案中用到的圖片。
src:存放專案的原始碼。
tmpclasses:存放編譯器產生的class檔案,是classes資料夾的映象。
tmplib:空,不知道有什麼用,是lib資料夾的映象。

現在該是使用J2ME說Hello World的時候了。選擇你最喜歡的文字編輯器,例如Editplus,
輸入下面的程式碼:
package fancy.test;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class HelloWorld extends MIDlet implements CommandListener
{
private Display display;
private Form props;

private Command exitCommand = new Command("Exit", Command.EXIT, 1);

public HelloWorld()
{
display = Display.getDisplay(this);
}

public void startApp()
{
props = new Form("Hello World");
props.append("Hello World!\n");

props.addCommand(exitCommand);
props.setCommandListener(this);
display.setCurrent(props);
}

public void commandAction(Command c, Displayable s)
{
if (c == exitCommand)
{
destroyApp(false);
notifyDestroyed();
}
}

public void destroyApp(boolean unconditional)
{
}

public void pauseApp()
{
display.setCurrent(null);
props = null;
}

}
然後將該檔案儲存在J2MEWTK_HOME\apps\fancy\src\fancy\test目錄下面,檔名為Hello
World.java。注意:你需要在fancy\src目錄下面建立fancy資料夾,然後再在fancy資料夾下面
建立test資料夾。最後才儲存HelloWorld.java檔案。
現在轉到J2MEWTK的主視窗,單擊Build按鈕,編譯整個專案,檢視控制檯的輸出資訊,一切無
誤,再單擊Run按鈕,執行此程式。執行效果如下圖所示:


要停電了,只好寫道這裡了。
1) package fancy.test;
這行程式碼宣告當前類所在的包。這是有必要的。而且這個包名必須和src資料夾中的目錄結
構對應。

2)
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
這兩行程式碼匯入必要的Java包,這兩個包的作用在後面會提及,這裡就不多說了。

3)
public class HelloWorld extends MIDlet implements CommandListener
J2ME程式一般應該繼承MIDlet,實現CommandListener。就如Applet必須繼承Applet,可能實
現Runnable介面一樣。

4)
private Display display;
private Form props;
定義兩個私有物件,Display代表螢幕,顯示區域。Form是容器的一種。在J2ME程式中,不但
有容器的概念,還有畫布(Canvas)的概念。這個程式在Form容器中顯示文字。

5)
private Command exitCommand = new Command("Exit", Command.EXIT, 1);
宣告一個Command物件。J2ME的事件處理機制和J2SE的事件處理機制不太一樣。在J2ME程式
中,必須預先定義一些Command物件,註冊到程式中。當裝置發生了某個事件,會產生相應的Co
mmand物件,並把它傳遞給一個事件處理函式----commandAction(),由它對所產生的事件做統
籌處理。

6)
public HelloWorld()
{
display = Display.getDisplay(this);
}
這個是建構函式,函式內部,呼叫Display物件的靜態方法---getDisplay(),獲取螢幕物件,
例項化display變數。這個呼叫是必要的。你可以在建構函式中做這個工作,也可以在startA
pp()方法中做這個工作。推薦在建構函式中完成。

7)MIDlet程式的執行流程
建構函式---->startApp()------>偵聽事件,接受命令------->commandAction()方法----
--->呼叫別的方法----------->如果是exit命令--------->pauseApp()--------->destroyA
pp()方法。實際上MIDlet程式的執行流程和Applet程式的執行流程差不多。

8)
public void startApp()
{
props = new Form("Hello World");
props.append("Hello World!\n");

props.addCommand(exitCommand);
props.setCommandListener(this);
display.setCurrent(props);
}
這是startApp()方法。這個方法是父類的抽象方法,在子類中必須予以覆蓋。首先例項化F
orm物件----------props,Form的建構函式的引數(Hello World)就是螢幕的標題。Form物件
是一容器,在裡面可以包含別的東西,props.append(“…..”);的作用就是在這個容器中存放
一個字串。這個字串會在螢幕中顯示出來。
接下來的三行程式碼分別做這樣的工作:
將Exit命令註冊到Form物件(props)中,這樣Form物件(props)可以對該命令作出響應。
設定Form物件(props)的命令監聽者。
將Form物件設定為螢幕顯示的物件。
你可以試著註釋掉這三行程式碼,再編譯執行這個程式,看看會發生什麼情況。

9)
public void commandAction(Command c, Displayable s)
{
if (c == exitCommand)
{
destroyApp(false);
notifyDestroyed();
}
}
這個方法是事件處理的中樞,它接受各種命令,並對其進行分析,再分別呼叫合適的處理方法
。在這個例子中,當接收到Exit命令以後,馬上銷燬程式,退出。

10)destroyApp()方法的作用是退出程式並銷燬程式物件。pauseApp()方法的作用是暫停程式
,並銷燬容器物件或者是畫布物件。手機螢幕將會是一片空白。

javax.microedition.lcdui:使用者介面包,主要用於構造程式的使用者介面。Command、Form都
是這個包的類。
javax.microedition.rms:這個包實現了對手機資料的存取功能。
javax.microedition.midlet:這個包是MIDlet程式的宣告週期包,主要定義了MIDlet類,MIDl
et類是一個抽象類,裡面宣告瞭startApp()、destroyApp()、pauseApp()等抽象方法。
javax.microedition.io:網路IO包。有HttpConnection介面和Connection介面、Datagram接
口。
java.io.*
java.lang.*
java.util.*
上面這三個包屬於J2ME核心包,J2ME中的核心包和J2SE中的同名核心包有些差別,主要是功能
大大簡化了,許多類、方法都沒有了,只能實現一些最基本的功能。

J2ME開發中有中文問題嗎?可能有,但是我目前沒有遇到。因為我沒有手機,只能在模擬器上
執行J2ME程式,真實的情況是什麼樣子我也不知道。在水木上有人說已經出現了中文問題,在
模擬器上好好的,到了真正的手機上卻是一團亂碼。我現在也沒有辦法,只有在遇到的時候再
補上這一節。我寫的測試程式如下所示,這個程式是在HelloWorld.java的基礎上改進而來的

package fancy.test;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.util.*;

public class Poem extends MIDlet implements CommandListener
{
private Display display;
private Form props;


private Command exitCommand = new Command("Exit", Command.EXIT, 1);

public Poem()
{
display = Display.getDisplay(this);
}

public void startApp()
{
props = new Form("影落寒潭的簽名檔");
props.append("小樓一夜聽春雨\n");
props.append("深巷明朝賣杏花\n\r");
props.append("虹虹的簽名檔\n");
props.append("鴛鴦獨宿何曾慣\n");
props.append("化作西樓一縷雲\n");
props.addCommand(exitCommand);
props.setCommandListener(this);
display.setCurrent(props);
}

public void commandAction(Command c, Displayable s)
{
if (c == exitCommand)
{
destroyApp(false);
notifyDestroyed();
}
}

public void destroyApp(boolean unconditional)
{
}

public void pauseApp()
{
display.setCurrent(null);
props = null;
}
}
使用普通的編輯器編輯好上述檔案以後,儲存為Poem.java,儲存路徑為src\fancy\test。然
後在Ktoolbar中編譯,一切無誤之後,單擊Setting按鈕,出現一個配置視窗,選擇MIDlets皮膚
,單擊Add按鈕,依次輸入Poem、fancy.png、fancy.test.Poem三項。單擊OK按鈕,再單擊OK按
鈕,關閉配置視窗,回到Ktoolbar的主介面,再次編譯。一切無誤之後,單擊Run按鈕執行程式。
Poem的執行效果如下圖所示。
注意:每新編寫一個程式,都要按照這個步驟進行配置,再編譯執行,我以後就不再重複描述
這個步驟了。


請看下面的程式碼(Prop.java):
package fancy.test;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.util.*;

public class Prop extends MIDlet implements CommandListener
{
private Display display;
private Form props;


private Command exitCommand = new Command("Exit", Command.EXIT, 1);

public Prop()
{
display = Display.getDisplay(this);
}

public void startApp()
{
props = new Form("System Properties");
props.append("Hello World!\n");
long time=System.currentTimeMillis();
props.append("current time:"+time+"\n");
props.append("microedition.configuration:"+
System.getProperty("microedition.configuration")+"\n");
props.append("microedition.profiles:"+
System.getProperty("microedition.profiles")+"\n");
props.append("microedition.platform:"+
System.getProperty("microedition.platform")+"\n");
props.append("microedition.locale:"+
System.getProperty("microedition.locale")+"\n");
props.append("microedition.encoding:"+
System.getProperty("microedition.encoding")+"\n");
props.append("java.version:"+System.getProperty("java.version")+"\n");//null
props.append("java.vendor:"+System.getProperty("java.vendor")+"\n");//null
props.append("java.vm.name:"+System.getProperty("java.vm.name")+"\n");//null
props.append("java.vm.version:"+System.getProperty("java.vm.version")+"\n");//
null
props.append("os.name:"+System.getProperty("os.name")+"\n");//null
props.append("os.arch:"+System.getProperty("os.arch")+"\n");//null
props.append("os.version:"+System.getProperty("os.version")+"\n");//null
props.append("user.name:"+System.getProperty("user.name")+"\n");//null
props.addCommand(exitCommand);
props.setCommandListener(this);
display.setCurrent(props);
}

public void commandAction(Command c, Displayable s)
{
if (c == exitCommand)
{
destroyApp(false);
notifyDestroyed();
}
}

public void destroyApp(boolean unconditional)
{
}

public void pauseApp()
{
display.setCurrent(null);
props = null;
}
}
這個程式的作用是輸出系統中各個環境屬性的值。訣竅是使用System類的getProperty()方
法。請注意,J2ME核心包的System類已經不支援getProperties()方法了,而且很多環境屬性都
不再支援了,比如java.version、java.vendor等等。


檢視記憶體利用情況
請看程式(Memory.java):
package fancy.test;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class Memory extends MIDlet implements CommandListener
{
private Display display;
private Form props;

private Command exitCommand = new Command("Exit", Command.EXIT, 1);

public Memory()
{
display = Display.getDisplay(this);
}

public void startApp()
{
props = new Form("Runtime Information");
long total=Runtime.getRuntime().totalMemory();
long free=Runtime.getRuntime().freeMemory();
props.append("total memory:"+total+"\n");
props.append("free memory:"+free+"\n");

props.addCommand(exitCommand);
props.setCommandListener(this);
display.setCurrent(props);
}

public void commandAction(Command c, Displayable s)
{
if (c == exitCommand)
{
destroyApp(false);
notifyDestroyed();
}
}

public void destroyApp(boolean unconditional)
{
}

public void pauseApp()
{
display.setCurrent(null);
props = null;
}

}
這個程式的訣竅是利用Runtime類的totalMemory()方法以及freeMemory()方法。J2ME中的
Runtime類不再具有執行外部程式的功能了,這是很顯然的。

List物件
發信站: 北大未名站 (2001年10月20日20:32:00 星期六) , 站內信件

List屬於javax.microedition.lcdui包,它和Form一樣,同樣屬於容器型別的物件。屬於容
器型別的物件還有TextBox和Alert。我們在下面還會介紹這兩個類的用法。此處首先介紹Li
st的用法。請看下面的程式(FormList.java):
package fancy.test;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class FormList extends MIDlet implements CommandListener
{
private Display display;
private List list;
private Command exitCommand = new Command("Exit", Command.EXIT, 1);

public FormList()
{
display = Display.getDisplay(this);
}

public void startApp()
{
list= new List("Choose URL", Choice.EXCLUSIVE);
list.append("www.pku.edu.cn",null);
list.append("www.yahoo.com",null);
list.append("fancyrainbow@263.net",null);

list.addCommand(exitCommand);
list.setCommandListener(this);
display.setCurrent(list);
}

public void commandAction(Command c, Displayable s)
{
if (c == exitCommand)
{
destroyApp(false);
notifyDestroyed();
}
}

public void destroyApp(boolean unconditional)
{
}

public void pauseApp()
{
display.setCurrent(null);
list = null;
}

}
請大家留意startApp()方法的內部:
list= new List("Choose URL", Choice.EXCLUSIVE);
list.append("www.pku.edu.cn",null);
list.append("www.yahoo.com",null);
list.append("fancyrainbow@263.net",null);

list.addCommand(exitCommand);
list.setCommandListener(this);
display.setCurrent(list);
其邏輯流程如下:首先呼叫建構函式例項化一個List物件(list),List物件實際上代表一個
選擇列表。List類的建構函式的第一個引數是選擇列表的名字,第二個引數是選擇列表的形式
, Choice.EXCLUSIVE表示這個選擇列表只能夠單選。如果是Choice.MULTIPLE,則表示這個選
擇列表可以多選。List類的append()方法有兩個引數,第一個引數是選擇項的描述,第二個參
數是一個Image物件,代表每個選擇項前面的小圖示。第二個引數可以是null值,但是第一個參
數是必須的。我們同樣可以使用addCommand()方法往List中註冊命令,也可以使用setComman
dListener()方法指定命令監聽者,這和Form是一樣的。在startApp()方法的最後,使用Displ
ay物件的setCurrent()方法將List物件設定為當前的螢幕顯示物件。
FormList.java程式的執行效果如下圖所示:

相關文章