官术网_书友最值得收藏!

2.2 建立MIDlet類(lèi)

Midlet Suite中至少要包含一個(gè)MIDlet類(lèi),它是整個(gè)程序執(zhí)行的入口處,由于MIDlet類(lèi)是抽象類(lèi),所以需要定義一個(gè)類(lèi)來(lái)繼承MIDlet類(lèi)。

首先由于MIDlet類(lèi)位于包javax.microedtion.midlet中,因此第一步需要在代碼程序中引入這個(gè)包:

import javax.microedtion.midlet.*;

注意:不要寫(xiě)成“import javax.microedtion.MIDlet.*;”。

接著需要擴(kuò)展MIDlet類(lèi),它的類(lèi)名就是要編寫(xiě)的主類(lèi)名,擴(kuò)展后的代碼如下:

import javax.microedition.midlet.MIDlet;
public class MyMIDlet extends MIDlet {
}

從Java語(yǔ)法上說(shuō),這樣一個(gè)空類(lèi)是可以編譯的,但實(shí)際上用Eclipse試圖編譯的時(shí)候會(huì)拒絕通過(guò),這是因?yàn)镸IDlet類(lèi)有3個(gè)抽象方法是必須實(shí)現(xiàn)的:

protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
}
    protected void pauseApp() {
    }
    protected void startApp() throws MIDletStateChangeException {
    }

當(dāng)然,可以選擇直接新建MIDlet類(lèi),那樣就簡(jiǎn)單很多了。

選擇“新建”→“J2ME Midlet”命令,如圖2-6所示,就會(huì)打開(kāi)如圖2-7所示的“J2ME Midlet”設(shè)置向?qū)ВO(shè)置類(lèi)的名稱(chēng)和相關(guān)屬性。

圖2-6 建立MIDlet類(lèi)

圖2-7 “J2ME Midlet”設(shè)置向?qū)?/p>

注意:由于建立的是MIDlet類(lèi),所以在超類(lèi)處已經(jīng)直接顯示為“javax.microedition.midlet.MIDlet”類(lèi),通過(guò)選擇“Unimplemented abstract methods”選項(xiàng)可以實(shí)現(xiàn)MIDlet類(lèi)的3個(gè)抽象方法。

當(dāng)設(shè)置結(jié)束完成后,系統(tǒng)會(huì)自動(dòng)生成如下代碼:

import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
public class Demo extends MIDlet {
public Demo() {
        // TODO 自動(dòng)生成構(gòu)造函數(shù)存根
}
protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
        // TODO 自動(dòng)生成方法存根
    }
    protected void pauseApp() {
        // TODO 自動(dòng)生成方法存根
    }
    protected void startApp() throws MIDletStateChangeException {
        // TODO 自動(dòng)生成方法存根
    }
}

2.2.1 midlet包介紹

通過(guò)javax.microedition.midlet包,MIDP定義了MIDlet的生命周期,以及MIDlet與運(yùn)行環(huán)境的交互方式。javax.microedition.midlet包總共包含兩個(gè)類(lèi):MIDlet和MIDletStateChangeException。

(1)MIDlet是一個(gè)抽象類(lèi),它是所有MIDP應(yīng)用程序必須要擴(kuò)展的父類(lèi)。MIDlet類(lèi)確保在運(yùn)行環(huán)境中應(yīng)用程序的必要方法在適當(dāng)?shù)臅r(shí)機(jī)被執(zhí)行。開(kāi)發(fā)者必須要實(shí)現(xiàn)MIDlet中定義的3個(gè)抽象方法,即startApp()、pauseApp()和destroyApp()。

(2)MIDletStateChangeException是一個(gè)異常類(lèi)。它是用來(lái)監(jiān)測(cè)MIDP應(yīng)用程序狀態(tài)的改變的,當(dāng)MIDlet從一個(gè)狀態(tài)轉(zhuǎn)移到另外一個(gè)狀態(tài)失敗的情況下就會(huì)被拋出。

midlet包整個(gè)層次結(jié)構(gòu)如圖2-8所示。

圖2-8 midlet包層次結(jié)構(gòu)

MIDlet是MIDP應(yīng)用程序的入口類(lèi),與Java應(yīng)用程序中含有main()方法的類(lèi)相似,在J2ME中管理MIDlet的是應(yīng)用程序管理軟件。

MIDlet初始化后需要有其他的資源與之配合才能正常工作。例如,創(chuàng)建所需的對(duì)象(用戶(hù)界面及功能類(lèi)等)、從持久性存儲(chǔ)空間讀取數(shù)據(jù)、新建線(xiàn)程并行處理任務(wù)及建立網(wǎng)絡(luò)連接讀取數(shù)據(jù)等。

2.2.2 MIDlet類(lèi)的生命周期

1.MIDlet的狀態(tài)

J2ME程序都是從MIDlet類(lèi)開(kāi)始執(zhí)行的,系統(tǒng)規(guī)定了MIDlet的生命周期。規(guī)定MIDlet程序有3種狀態(tài):運(yùn)行狀態(tài)、暫停狀態(tài)和銷(xiāo)毀狀態(tài)。

(1)運(yùn)行狀態(tài)。當(dāng)一個(gè)MIDlet進(jìn)入運(yùn)行狀態(tài)時(shí),它將獲得用于執(zhí)行任務(wù)的所有資源。轉(zhuǎn)移到運(yùn)行狀態(tài)之后,所需的線(xiàn)程應(yīng)該被啟動(dòng)。

(2)暫停狀態(tài)。當(dāng)一個(gè)MIDlet進(jìn)入暫停狀態(tài)時(shí),它應(yīng)該釋放所有持有的資源并停止活動(dòng)的線(xiàn)程。如果有需要,則應(yīng)該把數(shù)據(jù)保存到持久性存儲(chǔ)器中,這樣在程序重新進(jìn)入活動(dòng)狀態(tài)時(shí)可以重用。

(3)銷(xiāo)毀狀態(tài)。當(dāng)一個(gè)MIDlet進(jìn)入銷(xiāo)毀狀態(tài)時(shí),它應(yīng)該釋放所有資源、停止正在執(zhí)行的線(xiàn)程并保存持久性的數(shù)據(jù)。

系統(tǒng)在執(zhí)行MIDlet程序時(shí),首先構(gòu)造一個(gè)MIDlet類(lèi)型的對(duì)象,然后使程序進(jìn)入到暫停狀態(tài),按照生命周期的規(guī)定,系統(tǒng)會(huì)自動(dòng)調(diào)用MIDlet對(duì)象的startApp()方法使程序進(jìn)入到運(yùn)行狀態(tài),開(kāi)始程序的執(zhí)行。如果在創(chuàng)建MIDlet對(duì)象的過(guò)程中,或者是調(diào)用startApp()的方法中發(fā)生了異常,則系統(tǒng)會(huì)自動(dòng)調(diào)用MIDlet對(duì)象的destroyApp()方法進(jìn)行到銷(xiāo)毀狀態(tài),也就是使程序退出。

2.狀態(tài)轉(zhuǎn)換

應(yīng)用程序管理軟件(AMS)使用如圖2-9所示的生命周期方法來(lái)控制MIDlet的狀態(tài)。

默認(rèn)構(gòu)造器。當(dāng)用戶(hù)啟動(dòng)一個(gè)MIDlet時(shí),AMS創(chuàng)建一個(gè)新的MIDlet實(shí)例,通過(guò)調(diào)用默認(rèn)構(gòu)造器來(lái)執(zhí)行初始化工作。當(dāng)構(gòu)造器返回后,MIDlet被置于暫停狀態(tài)。如果在構(gòu)造器執(zhí)行期間拋出異常,那么MIDlet立即進(jìn)入銷(xiāo)毀狀態(tài)。

圖2-9 MIDlet類(lèi)的生命周期

public void startApp()方法。在MIDlet處于暫停狀態(tài)的時(shí)候,AMS調(diào)用startApp()方法指示MIDlet應(yīng)該進(jìn)入活動(dòng)狀態(tài)。startApp()方法可能會(huì)拋出MIDletStateChangeException,這個(gè)異常說(shuō)明MIDlet現(xiàn)在不能啟動(dòng),但是可能稍后會(huì)啟動(dòng)。如果阻止MIDlet啟動(dòng)的錯(cuò)誤是短暫性的,那么可以捕獲這個(gè)異常并從錯(cuò)誤中恢復(fù)。如果這個(gè)錯(cuò)誤是非短暫性的,那么應(yīng)該調(diào)用notifyDestroyed()方法,MIDlet進(jìn)入銷(xiāo)毀狀態(tài)。

public void pauseApp()方法。當(dāng)MIDlet在活動(dòng)狀態(tài)時(shí),AMS調(diào)用這個(gè)方法指示MIDlet將從活動(dòng)狀態(tài)進(jìn)入暫停狀態(tài)。

public void destroyApp(boolean unconditional)方法。AMS可以在MIDlet處于活動(dòng)或者暫停時(shí)調(diào)用這個(gè)方法,指示MIDlet將進(jìn)入銷(xiāo)毀狀態(tài)。參數(shù)unconditional代表了終止請(qǐng)求的類(lèi)型,如果unconditional為true,那么終止請(qǐng)求是強(qiáng)制執(zhí)行的。如果unconditional為false,那么終止請(qǐng)求是可自由決定的,MIDlet可以?huà)伋鯩IDletStateChangeException而持續(xù)運(yùn)行。

需要說(shuō)明的狀態(tài)是暫停狀態(tài),系統(tǒng)在程序運(yùn)行過(guò)程中,如果手機(jī)有來(lái)電,則系統(tǒng)會(huì)自動(dòng)地使MIDlet程序進(jìn)入到暫停狀態(tài),在進(jìn)入到暫停狀態(tài)以前,系統(tǒng)會(huì)自動(dòng)調(diào)用MIDlet對(duì)象的pauseApp()方法。當(dāng)電話(huà)接聽(tīng)完畢以后,系統(tǒng)會(huì)自動(dòng)使MIDlet程序進(jìn)入到運(yùn)行狀態(tài),在進(jìn)入到運(yùn)行狀態(tài)以前,系統(tǒng)還會(huì)自動(dòng)調(diào)用startApp()方法使系統(tǒng)進(jìn)入到運(yùn)行狀態(tài)。

3.控制MIDlet的狀態(tài)改變

AMS控制MIDlet的狀態(tài)改變,在代碼執(zhí)行到某一點(diǎn)可能需要狀態(tài)的改變。MIDlet類(lèi)提供了如下3個(gè)方法來(lái)允許一個(gè)MIDlet來(lái)控制它自己的狀態(tài)。

(1)resumeRequest()方法。MIDlet調(diào)用這個(gè)方法表明它本身已經(jīng)準(zhǔn)備好進(jìn)入活動(dòng)狀態(tài)了。

(2)notifyPaused()方法。該方法允許MIDlet主動(dòng)暫停自己。當(dāng)MIDlet處于活動(dòng)狀態(tài)時(shí),它可以調(diào)用notifyPaused()方法通知AMS MIDlet已經(jīng)主動(dòng)進(jìn)入暫停狀態(tài)。在必要的時(shí)候,AMS可以調(diào)用startApp()方法重新啟動(dòng)MIDlet,也可以調(diào)用destroyApp()方法來(lái)終止MIDlet。

(3)notifyDestroyed()方法。該方法允許MIDlet主動(dòng)銷(xiāo)毀自己。當(dāng)MIDlet處于活動(dòng)狀態(tài)時(shí),它可以調(diào)用notifyDestroyed()方法通知AMS MIDlet已經(jīng)主動(dòng)進(jìn)入了銷(xiāo)毀狀態(tài)。

必須注意的是,如果上述的3個(gè)通知方法被調(diào)用,那么AMS就不會(huì)再調(diào)用相應(yīng)的生命周期方法。例如,如果已經(jīng)調(diào)用了notifyPaused()方法,那么pauseApp()方法就不會(huì)主動(dòng)被調(diào)用。也就是相關(guān)的生命周期方法應(yīng)該先于通知方法之前調(diào)用。因此,經(jīng)常在退出應(yīng)用程序的代碼中看到如下的方法:

public void exitMIDlet(){
    try{
        destroyApp(false);
        notifyDestroyed();
    }catch(MIDletStateChangeException ex){
        ex.printStackTrace();
    }
}

如果exitMIDlet()方法中只是調(diào)用notifyDestroyed()方法,那么destroyApp()方法就不會(huì)被AMS方法自動(dòng)調(diào)用,這樣本來(lái)由destroyApp()方法完成的銷(xiāo)毀和狀態(tài)保存工作都沒(méi)有被完成。

2.2.3 編寫(xiě)并運(yùn)行MIDlet應(yīng)用程序

這里只是編寫(xiě)一個(gè)最簡(jiǎn)單的J2ME應(yīng)用程序,在自動(dòng)生成的框架內(nèi)輸入如下代碼:

import javax.microedition.lcdui.*;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
public class Demo extends MIDlet {
    Display display;
    Form form;
    public Demo() {
        display=Display.getDisplay(this);
        form=new Form("第一個(gè)實(shí)例");
    }
    protected void destroyApp(boolean arg0) throws MIDletStateChange Exception {
    }
    protected void pauseApp() {
    }
    protected void startApp() throws MIDletStateChangeException {
        display.setCurrent(form);
    }
}

說(shuō)明:

Display display; 定義Display對(duì)象display,是每個(gè)J2ME程序必有的對(duì)象,用于顯示手機(jī)屏幕。

Form form;定義Form對(duì)象form,是被顯示的對(duì)象。

display=Display.getDisplay(this);通過(guò)調(diào)用Display類(lèi)中的靜態(tài)方法getDisplay()生成display對(duì)象。

form=new Form("第一個(gè)J2ME程序!");調(diào)用Form類(lèi)中的構(gòu)造方法生成form對(duì)象。

display.setCurrent(form);display對(duì)象調(diào)用setCurrent()方法將form對(duì)象顯示在手機(jī)屏幕上。

選擇運(yùn)行菜單下的運(yùn)行命令,配置運(yùn)行環(huán)境如圖2-10所示。或者在左側(cè)包資源管理器中選中MIDlet類(lèi)并單擊鼠標(biāo)右鍵選擇運(yùn)行方式中的“Emulated J2ME Midlet”命令,運(yùn)行結(jié)果如圖2-11所示。

圖2-10 配置運(yùn)行環(huán)境

圖2-11 運(yùn)行結(jié)果

2.2.4 打包與混淆

為了在J2ME設(shè)備上安裝J2ME MIDlet套件,首先必須把它部署為JAD和JAR文件,這一過(guò)程稱(chēng)為打包。EclipseME內(nèi)建了打包生成JAD和JAR文件的支持。有兩種打包選項(xiàng):創(chuàng)建包(Create Package)和創(chuàng)建混淆包(Create Obfuscated Package)。

1.創(chuàng)建包

如果使用創(chuàng)建包,那么將把JAD和JAR文件輸出到在首選項(xiàng)(Preferences)中配置的部署目錄中。部署的JAR文件包含校驗(yàn)過(guò)的類(lèi)文件和資源文件。在J2ME項(xiàng)目上單擊鼠標(biāo)右鍵選擇“J2ME”下的“Create Package”命令即可,如圖2-12所示。

打包之后可以看到輸出目錄如圖2-13所示,在deployed文件夾中生成與項(xiàng)目同名的JAR文件和JAD文件。JAR文件是項(xiàng)目的安裝文件,可以將JAR文件復(fù)制到終端設(shè)備上,并進(jìn)行安裝。JAD文件是項(xiàng)目的信息描述文件,有的手機(jī)只需要JAR文件,有的兩者都需要。

圖2-12 打包菜單

2.創(chuàng)建混淆包

如果使用創(chuàng)建混淆包,則需要安裝混淆器,EclipseME會(huì)使用在首選項(xiàng)中指定的Proguard工具來(lái)混淆部署的JAR文件。混淆能夠?qū)IDlet進(jìn)行一定程度的保護(hù),增加反編譯的難度。更重要的是,混淆后的包通常會(huì)更小。

為了產(chǎn)生混淆包,需要正確安裝Proguard工具,并在混淆首選項(xiàng)(Obfuscation Preferences)中正確設(shè)置其安裝目錄。Proguard是一個(gè)免費(fèi)、開(kāi)源的工具,可以從http://proguard.sourceforge.net/下載。

在Eclipse環(huán)境下打包,右鍵單擊項(xiàng)目名稱(chēng),選擇“J2ME”→“Create Obfuscated Package”命令后就彈出一個(gè)警告框,如圖2-14所示。

圖2-13 打包后的菜單

圖2-14 “Obfuscation Error”對(duì)話(huà)框

這是因?yàn)闆](méi)有安裝混淆器,安裝混淆器Proguard至Eclipse的步驟如下。

(1)下載Proguard4.7.zip包,下載地址為http://sourceforge.net/projects/proguard/files/

(2)將下載后的Proguard4.7.zip包解壓縮。在Eclipse中操作如下:“窗口”→“首選項(xiàng)”→“J2ME”→“Packaging”→“Obfuscation”,在Proguard Root Directory增加混淆包路徑如圖2-15所示。

(3)J2ME項(xiàng)目打包:右鍵單擊項(xiàng)目名,選擇“J2ME”→“Create Obfuscated Package”命令。

JAR和JAD文件是在MIDP兼容的設(shè)備上部署應(yīng)用所必需的。除此之外,在混淆過(guò)程中還產(chǎn)生了一定數(shù)量的其他文件。這些文件和生成的JAR文件、JAD文件一起,被放在部署目錄中,如圖2-16所示。

*_base.jar:這個(gè)JAR文件包含混淆之前的初始包,被作為混淆處理的源。

*_base_obf.jar:這個(gè)JAR文件包含混淆后的class文件。對(duì)這個(gè)JAR文件進(jìn)行預(yù)校驗(yàn)處理就產(chǎn)生了最終的混淆并校驗(yàn)過(guò)的JAR文件。

pro_map.txt:這個(gè)文件包含了類(lèi)中原名和混淆后的名字的對(duì)應(yīng)關(guān)系。利用這個(gè)文件,就可以使用Proguard的ReTrace命令,來(lái)根據(jù)混淆后的追蹤輸出(stack trace)來(lái)重建原始的追蹤輸出。

pro_seeds.txt:這個(gè)文件列出了作為混淆種子(seed)的MIDlet子類(lèi)。

proguard.cfg:這個(gè)文件包含Proguard的混淆參數(shù)設(shè)置。

圖2-15 添加混淆器

圖2-16 混淆包文件目錄

主站蜘蛛池模板: 广昌县| 建始县| 宁安市| 洞口县| 广州市| 长沙县| 原平市| 深州市| 大厂| 秀山| 宜丰县| 依安县| 南郑县| 平阴县| 巴林右旗| 伊宁市| 马关县| 修武县| 辛集市| 临安市| 思茅市| 汾阳市| 萍乡市| 鹤庆县| 定西市| 东阳市| 石台县| 德清县| 汝州市| 方城县| 新丰县| 清涧县| 尼木县| 霍州市| 吉安县| 固阳县| 娄烦县| 黔东| 买车| 长顺县| 晋宁县|