论坛首页 移动开发技术论坛

MIDlet生命周期

浏览 3996 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-12-23   最后修改:2010-01-26
1.MIDlet生命周期方法

AMS使用如下生命周期方法来控制MIDlet的状态:

Ø 默认构造器。AMS调用默认构造来执行基本的初始化工作,如设置实例变量。此时MIDlet还处在暂停(Paused)的状态,它并没有获得任何所需的资源。

Ø  startApp()方法。AMS调用startApp()方法来获取MIDlet所需的资源,然后MIDlet将会处于活动(Active)状态。

Ø  pauseApp()方法。AMS调用pauseApp()方法来释放MIDlet持有的任何资源。如果MIDlet创建了对象,则将对象状态存储到持久性存储器中并把对象设置为Null。如果MIDlet启动了任何线程,则停止或者暂停这些线程。

Ø  destroyApp()方法。AMS调用destroyApp()方法来保存MIDlet的状态并释放MIDlet持有的任何资源。通常,一个设计良好的MIDlet应该在被关闭前进入此状态。

下面的代码框架包含了基本的生命周期方法,可以将其作为程序的模版。出色的开发工具在新建MIDlet的时候都会自动生成类似下面的框架,如Netbeans IDE。

import javax.microedition.midlet.*;



public class MyMIDlet extends MIDlet{

  

    public MyMIDlet(){

        //默认构造器

}



public void startApp(){

    //进入活动状态

}



public void pauseApp(){

    //进入暂停状态

}



public void destroyApp(Boolean unconditional){

    //进入销毁状态

}

}
2.MIDlet的状态

用户启动MIDlet之后,被启动的MIDlet将处于应用程序生命周期中的三个状态之一。可能的状态是暂停(Paused)、活动(Active)和销毁(Destroyed)。

Ø 活动状态。当一个MIDlet进入活动状态时,它将获得用于执行任务的所有资源。转移到活动状态之后,所需的线程应该被启动。

Ø 暂停状态。当一个MIDlet进入暂停状态时,它应该释放所有持有的资源并停止活动的线程。如果有需要,则应该把数据保存到持久性存储器中,这样在程序重新进入活动状态的时候可以重用。

Ø 销毁状态。当一个MIDlet进入销毁状态时,它应该释放所有资源、停止正在执行的线程并保存持久性的数据。

MIDlet的状态如图2-17所示。

AMS控制着MIDlet在上述三种状态中的迁移,通过调用MIDlet的生命周期方法来通知应用程序。读者需要仔细参考MIDP Java doc来熟悉MIDlet的状态迁移。这里总结如下:

Ø 默认构造器。当用户启动一个MIDlet的时候,AMS创建一个新的MIDlet实例,通过调用默认构造器来执行初始化工作。当构造器返回后,MIDlet被置于暂停状态。如果在构造器执行期间抛出异常,那么MIDlet立即进入销毁状态。

Ø  public void startApp()方法。在MIDlet处于暂停状态的时候,AMS调用startApp()方法指示MIDlet应该进入活动状态。startApp()方法可能会抛出MIDletState ChangeException,这个异常说明MIDlet现在不能启动,但是可能稍后会启动。如果阻止MIDlet启动的错误是短暂性的,那么你可以捕获这个异常并从错误中恢复。如果这个错误是非短暂性的,那么应该调用notifyDestroyed()方法,MIDlet进入销毁状态。

Ø  public void pauseApp()方法。当MIDlet在活动状态的时候,AMS调用这个方法指示MIDlet将从活动状态进入暂停状态。

Ø  public void destroyApp(boolean unconditional)方法。AMS可以在MIDlet处于活动或者暂停的时候调用这个方法,指示MIDlet将进入销毁状态。参数unconditional代表了终止请求的类型,如果unconditional为true,那么终止请求是强制执行的。如果unconditional为false,那么终止请求是可自由决定的,MIDlet可以抛出MIDletStateChangedException而持续运行。
3.控制MIDlet的状态改变

AMS控制MIDlet的状态改变,在代码执行到某一点你可能需要状态的改变。MIDlet类提供了如下三个方法来允许一个MIDlet来控制它自己的状态。

Ø  resumeRequest()方法。MIDlet调用这个方法表明它本身已经准备好进入活动状态了。resumeRequest()方法调用的结果是,AMS会在何时调用MIDlet的startApp()方法。

Ø  notifyPaused()方法。该方法允许MIDlet主动暂停自己。当MIDlet处于活动状态的时候,它可以调用notifyPause()方法通知AMS MIDlet已经主动进入暂停状态。在必要的时候,AMS可以调用startApp()方法重新启动MIDlet,也可以调用destroyApp()方法来终止MIDlet。

Ø  notifyDestroyed()方法。该方法允许MIDlet主动销毁自己。当MIDlet处于活动状态的时候,它可以调用notifyDestroyed()方法通知AMS MIDlet已经主动进入了销毁状态。

必须注意的是,如果上述的三个通知方法被调用,那么AMS就不会再调用相应的生命周期方法。例如,如果已经调用了notifyPaused()方法,那么pauseApp()方法就不会主动被调用。也就是相关的生命周期方法应该先于通知方法之前调用。因此,我们经常在退出应用程序的代码中看到如下的方法:

public void exitMIDlet(){

    try{

        destroyApp(false);

        notifyDestroyed();

    }catch(MIDletStateChangeException ex){

        ex.printStackTrace();

    }

}

如果exitMIDlet()方法中只是调用notifyDestroyed()方法,那么destroyApp()方法就不会被AMS方法自动调用,这样本来由destroyApp()方法完成的销毁和状态保存工作都没有被完成。图2-18说明了MIDlet的状态控制。
2.3.3  MIDlet套件

把一组MIDlet打包到一个jar文件然后发布,这个文件称做MIDlet套件。在MIDlet套件的内部有个Manifest.mf文件用于描述MIDlet套件的内容信息,其中就包含定义MIDlet套件中的MIDlet的属性。在同一个MIDlet套件中的MIDlet可以访问同样的资源,如类和数据,他们之间共享运行环境。

从物理组织上说,MIDlet套件包含如下的内容:

Ø 一个或者多个MIDlet,它们必须是javax.microedition.MIDlet的子类;

Ø  MIDlet的支持类,这些类是在CLDC和MIDP中都没有定义的,需要开发者自己创建,比如功能类等;

Ø 资源文件,如图片、文本和多媒体文件;

Ø  Manifest.mf文件用于描述MIDlet套件的信息。

MIDlet类是MIDlet套件中必须包含的,因为它定义了应用程序的生命周期。多个MIDlet可以打包在一个MIDlet套件中发布,这样开发者可以一次创建多个MIDlet。

MIDP规范中要求Manifest.mf文件,这是一个文本文件。它由名称和值组成,中间由“:”分隔。下面是一个典型的Manifest.mf文件的内容。

01Manifest-Version: 1.0

Ant-Version: Apache Ant 1.6.2

Created-By: 1.4.2_03-b02 (Sun Microsystems Inc.)

MIDlet-1: Mboker,/icon.png,com.mboker.blog.midp.MBokerMIDlet

MIDlet-Vendor: Vendor

MIDlet-Version: 1.0

MIDlet-Name: mboker

MicroEdition-Configuration: CLDC-1.0

MicroEdition-Profile: MIDP-2.0

每个MIDlet套件有个可选的JAD文件来描述MIDlet套件的信息,与Manifest.mf文件不同的是,JAD文件位于MIDlet套件的外部。虽然是可选的,但是JAD文件的作用非常重要。在MIDlet套件安装到移动设备之前,AMS首先会读取JAD文件的内容,分析MIDlet套件是否与设备实现兼容,比如配置和简表的版本是否匹配。如果不兼容,那么系统会拒绝安装这个套件。当用户从网络上下载MIDlet套件的时候,如果不进行这一步检查,就可能出现用户安装应用程序后不能够运行的问题,给用户造成不必要的浪费。JAD文件的格式与Manifest.mf的文件格式非常相似,都是以“:”来分隔名称和值的。

表2-2描述了在MIDlet套件中定义的属性。

表2-2  MIDlet套件中定义的属性

属    性


描    述


Manifest.mf


JAD文件

MIDlet-Name


标记MIDlet套件的名称


必需


必需

MIDlet-Version


标记MIDlet套件的当前版本号


必需


必需

MIDlet-Vendor


创建此套件的组织


必需


必需

MIDlet-n


标记MIDlet类的文件名称、图标和包含包结构的类名


必需


必需

属    性


描    述


Manifest.mf


JAD文件

MicroEdition-Profile


标记套件能够成功地运行所需的简表版本


必需


必需

MicroEdition-Configuration


标记套件能够成功地运行所需的配置版本


必需


必需

MIDlet-Jar-URL


指示AMS下载套件的地址





必需

MIDlet-Jar-Size


说明jar文件的大小,以字节为单位





必需

MIDlet-Description


描述套件


可选


可选

MIDlet-Icon


在设备上代表套件的图标


可选


可选

MIDlet-Info-URL


提供MIDlet套件的信息


可选


可选

MIDlet-Data-Size


指定套件用于持久性存储所需的最小字节数


可选


可选

MIDlet-Permission(MIDP2.0)


定义套件成功运行需要访问的受限API的许可


可选


可选

MIDlet-Permissions-Opt(MIDP2.0)


定义那些访问受限API非关键的许可


可选


可选

MIDlet-Push(MIDP2.0)


Push注册


可选


可选

MIDlet-Install-Notify(MIDP2.0)


定义接收套件安装状态的URL


可选


可选

MIDlet-Delete-Notify(MIDP2.0)


定义接收套件删除报告的URL


可选


可选

MIDlet-Delete-Confirm(MIDP2.0)


提示用户确认删除了套件


可选


可选
       

注:MIDlet-n,MicroEdition-Profile和MicroEdition-Configuration不必同时出现在JAD文件和Manifest.mf文件中,可以只出现在其中之一。

Manifest.mf文件和JAD文件都必须包含的三个属性MIDlet-Name,MIDlet-Version和MIDlet-Vendor必须一致,否则AMS会拒绝安装MIDlet套件。当用户安装MIDlet套件的时候,AMS会鉴别正在安装的套件是信任的(Trusted)还是非信任的(Untrusted)。根据套件类型的不同,AMS处理在两个文件中重复定义的属性时采取了如下方法。

Ø 信任套件。如果定义的属性在Manifest.mf和JAD文件中都出现,那么它们必须要一致。

Ø 非信任套件。如果定义的属性在Manifest.mf和JAD文件中都出现,那么JAD文件中的定义的属性值占先。

MIDP 2.0规范中定义了几个新属性,如MIDlet-Permission和MIDlet-Push。在第7章介绍MIDP 2.0的安全模型和PUSH注册机制时将详细讲解上述新属性。
2.3.4  MIDP应用程序的属性

MIDlet可以访问两种运行时的属性值:系统属性和应用程序属性。
1.系统属性

系统属性是在CLDC(Connected Limited Device Configuration)中定义的,属性值被写入底层的系统,我们可以读取它们,但是不能修改这些属性值。如果想读取一个系统属性值,那么可以使用System类的静态方法System.getProperty()来读取。有时候我们可能想读取特定手机的系统信息,比如IMEI号。解决办法就是去参考这款手机的开发指南和规范,比如,从SonyEricsson系列手机读取IMEI号,调用方法:System.getProperty ("com. onyericsson.imei"),这时将返回手机的IMEI号码,如IMEI 123456-00-123456-1-00。需要说明的一点是,在SonyEricsson P910上查询IMEI号码时,传递的字符串参数应该是com.sonyericsson.IMEI(IMEI须大写)。如果在不支持此项功能的手机上查询IMEI号时,将什么都不返回,例如,在T610上调用。

表2-3列举了系统属性。

表2-3  MIDP应用程序系统属性

JSR


属性名称


默 认 值

30


microedition.platform


null




microedition.encoding


ISO8859_1




microedition.configuration


CLDC-1.0




microedition.profiles


null

37


microedition.locale


null




microedition.profiles


MIDP-1.0

75


microedition.io.file.FileConnection.version


1.0




file.separator


依赖于底层实现




microedition.pim.version


1.0

118


microedition.locale


null




microedition.profiles


MIDP-2.0




microedition.commports


依赖于底层实现




microedition.hostname


依赖于底层实现

120


wireless.messaging.sms.smsc


依赖于底层实现

139


microedition.platform


依赖于底层实现




microedition.encoding


ISO8859-1




microedition.configuration


CLDC-1.1




microedition.profiles


依赖于底层实现

177


microedition.smartcardslots


依赖于底层实现

179


microedition.location.version


1.0

180


microedition.sip.version


1.0

184


microedition.m3g.version


1.0

185


microedition.jtwi.version


1.0

195


microedition.locale


依赖于底层实现




microedition.profiles


IMP-1.0

205


wireless.messaging.sms.smsc


依赖于底层实现

205


wireless.messaging.mms.mmsc


依赖于底层实现
2.应用程序属性

应用程序属性值是在应用程序描述符文件或者MANIFEST文件中定义的,当我们部署应用程序的时候可以定义应用程序属性。比如下面是一个典型的JAD文件内容。

MIDlet-1: HttpWrapperMidlet,httpwrapper.HttpWrapperMIDlet

MIDlet-Jar-Size: 16315

MIDlet-Jar-URL: HttpWrapper.jar

MIDlet-Name: HttpWrapper

MIDlet-Vendor: Vendor

MIDlet-Version: 1.0

MicroEdition-Configuration: CLDC-1.0

MicroEdition-Profile: MIDP-1.0

Which-Locale: en

其中Which-Locale就是应用程序属性值,我们可以通过MIDlet的成员方法getAppProperty()来得到它,代码片断如下:

import javax.microedition.midlet.*;



public class MyMIDlet extends MIDlet {



    private String suiteName;

    private String which_locale;



    public MyMIDlet(){

        suiteName = getAppProperty( "MIDlet-Name" );

        which_locale = getAppProperty("Which-Locale");

    }

    //这里省略了其他代码

}

属性值对大小写是敏感的,如果属性值在底层系统、JAD文件和Manifest文件中都没有定义的话,那么将返回Null。

熟悉MIDP应用程序的系统属性对我们开发灵活、强大的MIDlet至关重要。可以根据系统属性返回值来动态地生成应用程序的菜单。例如,通过判断底层系统是否支持MMAPI来决定应用程序中是否要添加摄像功能。下面的例子演示了如何在MIDlet中读取系统属性。

package com.j2medev.ch3.property;



import javax.microedition.lcdui.*;

import javax.microedition.midlet.*;



public class DetectMIDlet extends MIDlet {

  

    private static DetectMIDlet instance = null;

    private Display display = null;

    private Displayable form = null;

  

    public DetectMIDlet() {

        instance = this;

    }

  

    protected void startApp() {

        if(display==null) {

            //首次启动应用程序

            display = Display.getDisplay(this);

            form = new TestForm();

            display.setCurrent(form);

        } else{

            display.setCurrent(form);

        }

    }

  

    protected void pauseApp() {}

  

    protected void destroyApp(boolean unconditional) {}

  

    public static void quitApp() {

        instance.destroyApp(true);

        instance.notifyDestroyed();

        instance = null;

    }

}



class TestForm extends Form implements CommandListener {

  

    private Command exit = new Command("退出", Command.EXIT, 0);

  

    public TestForm() {

        super("J2ME平台测试");

        String s;

        //CLDC版本属性

        s = System.getProperty("microedition.configuration");

        append(getValue("CLDC版本", s));

        //MIPD版本属性

        s = System.getProperty("microedition.profiles");

        append(getValue("MIDP版本",s));

      

        s = System.getProperty("microedition.platform");

        append(getValue("软件平台", s));

      

        s = System.getProperty("microedition.encoding");

        append(getValue("系统编码", s));

      

        s = System.getProperty("microedition.locale");

        append(getValue("区域设置", s));

      

        s = System.getProperty("microedition.jtwi.version");

        append(getValue("JTWI", s));

      

        //判断是否支持MMAPI

        s = System.getProperty("microedition.media.version");

        append(getValue("MMAPI", s));

        //判断是否支持WMA

        s = System.getProperty("wireless.messaging.sms.smsc");

        if(s!=null) {

            append(getValue("WMA", "支持"));

            append(getValue("SMS", s));

            s = System.getProperty("wireless.messaging.mms.mmsc");

            append(getValue("MMS", s));

        } else

            append(getValue("WMA", null));

        //判断是否支持蓝牙

        s = System.getProperty("bluetooth.api.version");

        append(getValue("蓝牙", s));

        //判断是否支持个人信息管理

        s = System.getProperty("microedition.pim.version");

        append(getValue("PIM", s));

        //判断是否支持文件系统

        s=System.getProperty("microedition.io.file.FileConnection. version");

        append(getValue("FileConnection", s));

        //判断是否支持SIP

        s = System.getProperty("microedition.sip.version");

        append(getValue("SIP", s));

        //判断是否支持M3G JSR 184

        s = System.getProperty("microedition.m3g.version");

        append(getValue("M3G", s));

        addCommand(exit);

        setCommandListener(this);

    }

  

    private String getValue(String prompt, String s) {

        return prompt + ":" + (s==null ? "不支持" : s) + "\n";

    }

  

    public void commandAction(Command c, Displayable d) {

        if(c==exit){

            DetectMIDlet.quitApp();

        }

    }

}

DetectMIDlet的运行界面如图2-19所示。

图2-19  DetectMIDlet的运行界面
2.3.5  发布MIDP应用程序

MIDlet开发完成后,需要进行一系列的测试。测试通过后我们就可以发布MIDlet套件了。本节讲述如何搭建OTA(Over The Air)下载服务器来发布MIDP应用程序。

OTA是指通过无线网络下载和安装J2ME应用程序的方案。搭建OTA服务器是比较简单的,但是做一个完整的OTA解决方案却非常复杂,因为这要设计到软件的管理、下载计费和安全认证等多个问题。

当手机通过无线网络发出请求要求下载相关软件的时候,通常是访问特定的页面,页面可以使用WML语言编写。客户端(手机)首先发送获得JAD文件的请求,服务器接收到请求后把JAD文件发送给客户端,客户端根据MIDlet-Jar-URL的信息请求下载jar文件,服务器响应请求并把jar包传输给客户端,客户端接收数据并开始安装软件。原理如图2-20所示。

我们采用Tomcat 5.0作为OTA下载服务器,请参考附录B来正确安装并运行Tomcat 5.0。假设安装目录为C:\Tomcat 5.0,使用文本编辑器打开C:\Tomcat 5.0\conf\web.xml文件,查看服务器是否支持jad和jar两种MIME类型,内容如下:

<mime-mapping>

  <extension>jad</extension>

  <mime-type>text/vnd.sun.j2me.app-descriptor</mime-type>

</mime-mapping>

<mime-mapping>

  <extension>jar</extension>

  <mime-type>application/java-archive</mime-type>

</mime-mapping>

如果采用的Tomcat服务器版本比较早,可能不支持上述两种MIME类型,需要手动把上述XML格式的内容添加到web.xml文件中。接下来编写一个WML文件down.wml作为下载页面,内容如下:

<?xml version="1.0"?>

<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"

"http://www.wapforum.org/DTD/wml_1.1.xml">

<wml>

<card title="Welcome" id="main">

<p>Software center:</p>

<p align="left">

<a href="UIDemo.jad">

UIDemo</a></p>

</card>

</wml>

将down.wml放置到C:\Tomcat 5.0\webapps\ROOT,这样我们可以使用手机语句http://yourserver:port/down.wml下载页面。我们使用WTK2.2自带的UIDemo作为下载文件,将UIDemo.jar和UIDemo.jad文件复制到C:\Tomcat 5.0\webapps\ROOT目录下。

WTK2.2提供了通过OTA的方式运行MIDP应用程序的功能。单击【开始】→【所有程序】→【J2ME Wireless Toolkit 2.2】→【OTA预配置】,启动AMS的安装管理器。单击【应用程序】按钮进入已安装软件列表中,选择“安装应用程序”进入URL输入界面。输入http://localhost:8080/down.wml(读者根据自己服务器的IP地址和端口号填写),然后单击【转到】命令,如图2-21所示。



图2-21  安装UIDemo套件

AMS安装器首先解析down.wml文件,把其中含有的UIDemo显示在列表中。单击【安装】按钮后AMS安装器就会读取UIDemo.jad文件并解析文件内容,然后显示在安装界面内,提示用户是否要安装UIDemo。这时,单击【安装】按钮即可开始安装MIDlet套件。安装完成后UIDemo会出现在已安装的应用程序列表中。安装过程如图2-22所示。



图2-22  安装UIDemo套件

论坛首页 移动开发技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics