请输入您要查询的百科知识:

 

词条 xlet
释义

xlet概述

Java手机核心技术MIDP建立在CLDC(Connected Limited Device Configuration)的基础上。Sun于2002年9月发布了J2ME Personal Profile 1.0,但和MIDP不同的是,Personal Profile建立在CDC(Connected Device Configuration)的基础上。CDC提供了一个功能完整的Java 2虚拟机,和CLDC相比,CDC要求有更高的内存和更可靠的网络连接。

Personal Profile包含了完整的AWT API集,支持图形用户接口(GUI),支持Applet和Xlet,为高端PDA应用提供了一个完整的开发、运行环境。

Xlet应用模型继承自Personal Basis Profile,是Personal Profile最重要的特色之一。什么是Xlet呢?就象J2SE环境下的Applet,Xlet也是一种必须在宿主(应用程序管理器)之内运行的应用。也就是说,Xlet本身不包含main()方法,不能作为独立的应用程序运行。但是,Xlet总是实现一组让应用程序管理器控制其状态的接口。

和J2SE领域的Applet相比,Xlet在J2ME领域的地位可能重要得多——设想一下,PDA将能够下载各种第三方的Xlet应用,轻松实现PDA功能的动态扩展;甚至一个Xlet可以通过互操作机制提供对其他Xlet的服务,从而开发出由多个模块化Xlet构成的类似客户机/服务器体系的复杂应用。

Xlet生命周期

每一个Xlet必须实现javax.microedition.xlet.Xlet接口定义的四个方法: public interface Xlet {

public void initXlet(XletContext ctx) throws XletStateChangeException;

public void startXlet() throws XletStateChangeException;

public void pauseXlet();

public void destroyXlet(boolean unconditional) throws

XletStateChangeException;

}

和Applet一样,对于Xlet来说生命周期也是一个很重要的概念。Xlet的应用程序管理器正是通过上述四个方法来控制Xlet的状态。要理解Xlet编程,首先必须理解Xlet的生命周期。

Xlet的生命周期包括下面四种状态:

一 装入(Loaded):已经从本地存储器或网络装入Xlet,且已调用其不带参数的构造函数。此时如果调用Xlet的initXlet()方法,Xlet可以转入暂停状态。

二 暂停(Paused):Xlet已初始化,且已做好激活的准备,相当于进程的“已准备好”状态——已经做好了随时在CPU上运行的准备。这时如果调用Xlet的startXlet()方法,它就进入活动状态。

三 活动(Active):Xlet正在正常运行。如果调用Xlet的destoryXlet()方法,则它进入“拆除”状态,如果调用pauseXlet()方法,则进入暂停状态。

四 拆除(Destroyed):这是Xlet的终止状态。进入已拆除状态的Xlet不能再转入其他状态,Xlet占用的所有资源将被回收。

Xlet可以从任何其他状态转入拆除状态。图1显示了Xlet各种状态的关系。

图1

实现Xlet接口

javax.microedition.xlet.Xlet接口定义的方法也称为“生命周期方法”。必须注意的是,用户应用程序(包括Xlet本身)不应该直接调用生命周期方法——即使强行调用,Xlet的状态也不会改变。生命周期方法应当由管理器调用,管理器通过生命周期方法来通知Xlet改变其状态。从这个意义上来看,生命周期方法就象是一种事件句柄。

initXlet(XletContext ctx)

管理器装入并实例化Xlet之后,调用initXlet()方法初始化Xlet。initXlet()的参数是一个XletContext,这个参数很重要,它是Xlet获取其运行上下文环境的唯一途径。XletContext类不仅提供了一些方法来提取传递给Xlet的参数,而且还有一个可供Xlet放置AWT组件的容器,更重要的是,Xlet本身还可以通过XletContext发出状态变换命令以及与其他Xlet通信。

startXlet(),pauseXlet()

startXlet()方法告知Xlet开始提供服务,并将Xlet转入活动状态。pauseXlet()的功能恰好相反:要求Xlet停止服务,并将其转入暂停状态。

initXlet()和startXlet()主要的不同之处在于:前者只能调用一次,对于后者,当管理器希望Xlet进入或者重新进入活动状态时可以多次调用。因为startXlet()可能被多次调用,所有只能执行一次的初始化工作应当在initXlet()而不是startXlet()中进行。

通常而言,类似startXlet()方法的位置是放置某些业务逻辑的好地方。但是,Personal Profile规范指出Xlet接口中定义的所有方法只能用于状态转换,Xlet应用管理器要求这些方法尽快返回。如果生命周期方法没有在一定的时间内(与具体的应用实现有关)返回,管理器将认为遇到了错误,直接拆除Xlet。因此,不应该在任何生命周期方法内放置长时间执行的业务逻辑,如果Xlet需要提供某种可反复启动、停止的服务,可以考虑用一个专用的线程来提供服务,生命周期方法通过与该服务线程的通信来控制服务的启动、停止,例如由生命周期方法设置一个服务启动/停止的标记。

destroyXlet(boolean unconditional)

该方法通知Xlet结束运行,转入拆除状态。Xlet应当释放所有的资源。参数unconditional由管理器设置,表示是否要无条件地拆除Xlet。如果unconditional是false,Xlet可以抛出一个StateChangeException异常,表示自己不想被拆除——但是,是否接受Xlet请求最终还是由管理器决定。也就是说,虽然Xlet有权合法地抛出StateChangeException异常,但最终决定其命运的还是管理器。如果管理器接受了Xlet要求不拆除的请求,它会给Xlet一些时间,一定的时间后再次调用destory()方法,这次unconditional一般会设置成true。当unconditional参数是true时,管理器将忽略任何XletStateChangeException异常,一旦destoryXlet()返回就直接拆除Xlet。

可以从生命周期方法抛出的异常有两种:XletStateChangeException,未被捕获的RuntimeException或错误。

如果生命周期方法抛出了未处理的RuntimeException或错误,管理器将立即调用Xlet的destoryXlet(true)方法,将Xlet拆除。因此,Xlet应当捕获所有“正常的”(原因已知的)RuntimeException或错误,避免将RuntimeException直接抛给管理器从而导致Xlet被拆除。相对而言,XletStateChangeException可以由Xlet有意地抛出,表示Xlet尚未做好改变状态的准备。

通过XletContext转换状态

如前所述,Xlet接口中定义的生命周期方法是供管理器通知Xlet转换状态用的。那么,如果Xlet本身想要转换状态,例如用户想要结束Xlet(但不想等待管理器发出停止Xlet的命令),又该如何进行呢?

XletContext提供了三个方法让Xlet发出转换状态通知,分别是:notifyDestroyed(),notifyPaused(),和resumeRequest()。notifyDestroyed()告诉管理器Xlet想要结束运行。就象调用destroyXlet()一样,在调用notifyDestroyed()之前Xlet应当释放所有的资源。调用notifyDestroyed()之后Xlet将立即无条件地转入拆除状态。

notifyPaused()将Xlet转入暂停状态。Xlet可以通过调用notifyPaused()为其他Xlet让出运行资源。一般地,后继的resumeRequest()调用能够把Xlet返回到活动状态,但正如该方法名称所示的,调用resumeRequest()只是发出了一个请求,而该请求能否被接受是没有办法保证的,最终要由管理器来决定Xlet是否可以返回、何时返回活动状态——Xlet可能要等待一段较长的时间才能返回活动状态,可能根本不能返回活动状态;或者,由于缺少资源,管理器可能调用destroyXlet()来结束一个暂停的Xlet。

开发实例:数字时钟

下面通过一个简单的实例示范Xlet的开发。这个Xlet是一个简单的数字时钟,显示出当前的小时、分钟、秒,用户可以随时暂停或终止时钟。这个时钟可以通过它本身的按钮控制,也可以通过管理器调用Xlet的生命周期方法来控制。Sun为Personal Profile提供了一个参考实现,其管理器称为XletRunner()。如果在XletRunner中运行时钟Xlet,用户可以通过XletRunner的菜单来控制时钟状态,例如要暂停时钟,除了点击时钟的“暂停”按钮,还可以选择XletRunner的ClockXlet菜单并选择pause。

下面是时钟Xlet的完整代码。

import javax.microedition.xlet.*;

import java.util.*;

import java.awt.*;

import java.awt.event.*;

public class ClockXlet implements Xlet, ActionListener {

TextField display;

MyClock clock;

Button pauseButton = new Button("暂停");

Button stopButton = new Button("停止");

Button resumeButton = new Button("继续");

XletContext context;

public void initXlet(XletContext ctx) throws

XletStateChangeException{

Container c;

context = ctx;

try {

c = ctx.getContainer();

} catch (UnavailableContainerException e) {

throw new XletStateChangeException(e.getMessage());

}

display = new TextField(30);

clock = new MyClock(display);

pauseButton.addActionListener(this);

resumeButton.addActionListener(this);

resumeButton.setEnabled(false);

stopButton.addActionListener(this);

c.setSize(200, 200);

c.setVisible(true);

c.add(display);

c.add(pauseButton);

c.add(resumeButton);

c.add(stopButton);

clock.start();

}

public void startXlet() {

clock.setPaused(false);

resumeButton.setEnabled(false);

pauseButton.setEnabled(true);

}

public void pauseXlet() {

clock.setPaused(true);

resumeButton.setEnabled(true);

pauseButton.setEnabled(false);

}

public void destroyXlet(boolean unconditional) {

clock.setStopped(true);

}

public void actionPerformed(ActionEvent e) {

if (e.getSource() == stopButton) {

clock.setStopped(true);

context.notifyDestroyed();

} else if (e.getSource() == pauseButton) {

clock.setPaused(true);

resumeButton.setEnabled(true);

pauseButton.setEnabled(false);

context.notifyPaused();

} else if (e.getSource() == resumeButton) {

context.resumeRequest();

} } }

class MyClock extends Thread {

boolean paused, stopped;

TextField display;

public MyClock(TextField t) {

display = t;

}

String getTime() {

Calendar rightNow = Calendar.getInstance();

String hour = String.valueOf(rightNow.get(Calendar.HOUR_OF_DAY));

String min = String.valueOf(rightNow.get(Calendar.MINUTE));

if (min.length() == 1) {

min = "0" + min;

}

String sec = String.valueOf(rightNow.get(Calendar.SECOND));

if (sec.length() == 1) {

sec = "0" + sec;

}

return hour + ":" + min + ":" + sec;

}

public synchronized boolean isStopped() {

return stopped;

}

public synchronized void setStopped(boolean value) {

stopped = value;

notifyAll();

}

public synchronized boolean isPaused() {

return paused;

}

public synchronized void setPaused(boolean value) {

paused = value;

notifyAll();

}

public void run() {

while (!isStopped()) {

try {

if (!isPaused()) {

Thread.sleep(1);

display.setText(getTime());

} else {

synchronized (this) {

wait();

}

}

} catch (InterruptedException e) {

} } } }

首先来看看MyClock类,它的主要功能是在一个TextField中显示出当前时间。MyClock类扩展了Thread类,其主要功能在run()方法中实现。MyClock类用两个标记来表示是否出现了暂停或停止请求;如果没有这类请求,时钟将正常运行,每隔1秒刷新当前时间。如果已出现暂停请求,时钟转入等待状态,直至暂停标记被清除再次唤醒线程。如果出现了停止时钟的请求,线程结束运行。

MyClock由ClockXlet控制。initXlet()方法首先创建一个供MyClock使用的TextField,以及几个用来控制时钟的按钮。然后,它启动MyClock的线程。这里的startXlet()和pauseXlet()都很简单,很快就可以返回(记住,生命周期方法应当尽快返回),其主要功能就是设置/取消MyClock的暂停标记,从而起到暂停/继续执行MyClock线程的作用。destroyXlet()方法设置MyClock的停止标记,从而终止线程执行。

actionPerformed()方法把用户的动作转换成对管理器的状态变换请求。点击时钟的“暂停”按钮暂停时钟运行,同时它还通过调用XletContext.notifyPaused()向管理器发送要求进入暂停状态的请求。点击“继续”按钮时Xlet发送一个要求返回活动状态的请求,如果管理器接受了请求,它就会调用Xlet的startXlet()方法,时钟继续运行。对于点击“停止”按钮的事件,处理方式也相似。

我们可以用Sun的Personal Profile参考实现提供的管理器XletRunner来测试ClockXlet。首先要从(由于百度不能提供网址链接,故去掉http!去sun java 下载!百度真垃圾,偷别人的东西,还不允许给他人打个标签)products/ personalprofile/download.html下载管理器。Sun在下载页面中声明该版本的运行环境(当前唯一可免费下载的版本)只能用于Linux 2.2或更高的机器上,其他版本属于商业软件。但经过测试,我发现它在XP下也运行得很好,如图2所示。

以Windows XP环境为例,从Sun网站下载得到的是一个ZIP文件,解开压缩,不必理会它的运行需求说明,只要将j2me-pp1.0\\lib里面的内容全部复制到Java源文件所在目录。用javac -classpath personal.jar ClockXlet.java命令编译。完成后,用java -cp personal.jar com.sun.xlet.XletRunner -name ClockXlet -path c:/test/ClockXlet命令就可以启动ClockXlet。

总结:Xlet和Applet一样,只能在管理器中运行。在Xlet编程中,状态转换是极其重要概念,每一个Xlet都必须实现接口规范定义的四个生命周期方法。Xlet本身不能直接调用生命周期方法,但可以通过XletContext请求变换自身的状态。

随便看

 

百科全书收录4421916条中文百科知识,基本涵盖了大多数领域的百科知识,是一部内容开放、自由的电子版百科全书。

 

Copyright © 2004-2023 Cnenc.net All Rights Reserved
更新时间:2025/3/22 23:10:11