摘要
在这个MIDP系列的最后一部分,我将介绍MIDlet和外部系统之间的通信方法。使用Java2 Micro Edition的MIDP中包含的API,开发者可以与外部的系统交互。这篇文章将以一个详细的例子介绍这些API,它演示了J2ME设备和一个基于servlet的Web系统可以进行的交互。
在前面的两个部分,我介绍的MIDP API的特性和功能都是和设备自身的运作和信息存储相关的。在这个最后的部分,我将集中介绍网络设备和大型网络的交互。
网络设备可以使用数不清的协议来进行互相通信。在这篇文章中,我将集中介绍HttpConnection接口,你可以通过它来访问存储在一个Web服务器上的信息。在介绍本文的例子之前,我将讨论javax.microedition.io接口和类的交互,而例子则集中介绍一个MIDP设备和一个基于JSP系统之间的交互。
Connection层次
javax.microedition.io包中的所有接口都是基于Connection接口的。其它的连接接口继承Connection中的方法,并且定义了用来访问相关变量和该Connection类型动作的方法。我将在本文中谈论最常用的接口,其它的接口留给读者研究。
HTTPConnection说明
HTTPConnection接口建立在Connection接口上,它还提供了一些其它的方法来进行HTTP交互。以下就是其中一些有用的方法列表:
String getHeaderField(int index)
String getHeaderField(String name)
long getHeaderFieldDate(String name, long def)
int getHeaderFieldInt(String name, int def)
String getHeaderFieldKey(int n)
String getHost()
long getLastModified()
int getPort()
String getProtocol()
String getQuery()
String getRef()
String getRequestMethod()
String getRequestProperty(String key)
int getResponseCode()
String getResponseMessage()
String getURL()
void setRequestMethod(String method)
void setRequestProperty(String key, String value)
这些方法可让你如基于servlet的系统一样访问HTTP字段。
其它的接口在API规范文档中有明确的定义。这些接口带有一些方法,可以使用不同的协议与设备收发数据包或者流数据。在这里我将不会很详细地讨论这些,因为在形式上是一样的。
Connector对象
MIDP API如何知道要创建哪个接口并返回给调用的类呢?答案是返回的Connector是根据传送给连接字符串的值。
以下的连接字符串是提醒Connector对象系统正在查找一个HttpConnection:
HttpConnection httpConn = Connector.open("
http://www.itpath.com"); MIDP Connector对象分析连接的字符串,知道这是一个用作访问网页的URL,于是就会返回一个HttpConnection接口的实现给调用的类。
其它的连接协议需要不同的连接字符串。下表就是它们的一个列表:
协议 连接字符串
Http
http://www.yahoo.com Stream-based Socket Socket://localhost:6160
Datagram-based Socket - listening datagram://:6160
Datagram-based Socket - sending datagram://121.232.121.232:6160
Serial Port comm.:0;baudrate=5000
File file://helloWorld.txt
例子
以下的例子将本文讨论的东西都结合在一起。在这个例子中,MIDlet访问存储在一个远程系统上的信息。该信息以一个XML的形式返回给MIDlet。通过分析该XML,MIDlet就会根据这些数据构造一个用户界面。
用户界面由一个问题构成。用户提交后将会请求服务器将数据加进去。然后返回更新的数据给用户。
通过这个详细的例子,你可以对J2ME Connection API的基本用法和语法有更进一步的了解。
VoterMidlet
VoterMidlet是本例子中唯一的MIDlet。在下载时,它创建VoteResults对象的一个实例:
public class VoterMidlet extends MIDlet implements ScreenCallback
{;
private Display _display;
// midlet has three screens
private VoteResults voteResults = new VoteResults(
(ScreenCallback) this);
public VoterMidlet()
{;
_display = Display.getDisplay(this);
_display.setCurrent(voteResults);
};
public void exit()
{;
try
{;
this.destroyApp(true);
}; catch (MIDletStateChangeException e)
{;};
};
...
};
ScreenCallback
如上所示,VoterMidlet实现了ScreenCallback接口。该接口将UI类和一些事件隐藏起来,否则UI类可能需要一个到MIDlet的引用。ScreenCallback接口包含有一个单一的方法public void exit(),UI屏幕使用这个方法来提醒MIDlet,用户已经按下“Exit”按钮。
通过为ScreenCallback写代码,其它的MIDlet方法就与UI屏幕的开发者无关。这是很重要的,因为如果使用不当,一些MIDlet方法会给程序带来破坏性的后果。
VoteResults
VoteResults是一个用户接口类,用来显示投票的结果给用户。为了让例子简化,该接口实现了两个Model-View-Controller类:View和Controller。
该构造器由MIDlet中接收唯一一个参数--ScreenCallback接口。如上所述,该接口可让Screen能够回调MIDlet的一些方法。
构造器初始化该对象并且创建例子的用户界面,以下是其中令人感兴趣的部分:
VoteSummary voteSummary = ResourceUtility.getVoteSummary();
initialize(voteSummary);
以上的代码是负责初始化MIDlet和JSP页面的通信,它模拟的是一个真实的系统。ResourceUtility通过HTTP参数访问一个URL,并且由该JSP中得到信息。它使用该信息来创建一个VoteSummary对象。在后面的例子中我们还将进一步讨论这个接口。
然后就会调用initialize()方法来创建UI显示,它包括有两个StringItems显示前面的投票结果,还有一个ChoiceGroup包含有所有可能的投票和相应的投票值:
public void initialize(VoteSummary voteSummary)
{;
append( getNumVotesString( voteSummary.getNumVotes() )) ;
append( getAvgVoteString( voteSummary.getAvgVote() ));
append( showVoteResults( voteSummary.getVotes() ));
};
当用户输入时,就会调用commandAction()方法。该方法接收设备的输入。如果输入的命令是“Vote”,当前的选项就会由ChoiceGroup中得到。这时就会构造一个Vote对象,并且传送给ResourceUtility.addEntry()方法。该方法就会将信息传送给JSP,JSP就会将新投票加入到记录中,并且返回一个更新的VoteSummary对象。然后它就会调用update()方法:
public void commandAction(Command c, Displayable s)
{;
String command = c.getLabel();
if ( command.equals("Exit") )
{;
_screenCallback.exit();
};
else if ( command.equals("Vote") )
{;
// get the selected item
int selectedIndex = _voteResults.getSelectedIndex();
Vote newVote = new Vote(""+ selectedIndex, null, null);
VoteSummary voteSummary = ResourceUtility.addEntry( newVote);
update( voteSummary );
};
};
VoteSummary
VoteSummary对象包含有当前投票的状态信息。它跟踪全部的投票数字,平均的投票,以及维护投票的一个Vector(可得到每个选项的投票信息):
public VoteSummary(String numVotes, String avgVote, Vector votes)
{;
_numVotes = numVotes;
_avgVote = avgVote;
_votes = votes;
};
根据由JSP返回到MIDlet的XML,就会创建VoteSummary对象。
ResourceUtility
ResourceUtility类由远程服务器上得到XML信息。它使用HttpConnection由JSP中得到XML,然后就会通过XMLUtil 将这些XML转换为一个VoteSummary 对象:
public static VoteSummary getVoteSummary()
{;
String xml = loadVoteResults();
return convertXMLToVoteSummary( xml);
};
上面的getVoteSummary()方法访问这个对象。该方法会依次调用loadVoteResults()和convertXMLToVoteSummary()方法。loadVoteResults()方法如下所示,它调用了backendComms()方法,该方法用来为后台系统增加投票:
public static String loadVoteResults()
{;
return backendComms(LOAD_URL, "");
};
private static String backendComms(String requestURL, String requeststring)
{;
HttpConnection httpConnection = null;
DataInputStream dataInputStream = null;
StringBuffer messagebuffer = new StringBuffer();
String requestString = requestURL + requeststring;
Try
{;
// Open an HTTP connection with the Web server
httpConnection = (HttpConnection)
Connector.open(requestString, Connector.READ_WRITE);
// Set the request method to GET
httpConnection.setRequestMethod(HttpConnection.GET);
// Retrieve the response back from the servlet
dataInputStream =
new DataInputStream(httpConnection.openInputStream());
int inputChar;
// Check the Content-Length first
long contentLength = httpConnection.getLength();
if(contentLength!=-1)
{;
for(int i = 0;I {;
if((inputChar = dataInputStream.read())!= -1)
{;
messagebuffer.append((char)inputChar);
};
};
}; else {;
// if the content-length is not available
while ((inputChar = dataInputStream.read()) != -1)
{;
messagebuffer.append((char) inputChar);
};
};
dataInputStream.close();
}; catch (IOException ioe) {;
messagebuffer = new StringBuffer("ERROR!");
}; catch (Exception e){;
e.printStackTrace();
}; finally {;
try {;
if (httpConnection != null){
httpConnection.close();
}; catch (IOException ignored) {;};
try {;
if (dataInputStream != null)
dataInputStream.close();
}; catch (IOException ignored) {;};
};
return messagebuffer.toString();
};
以下我们讨论一下backendComms()方法。首先由try-catch块开始。第一步是打开一个到服务器的读/写HttpConnection。上面我已经说过,该方法得到XML并且对服务器发出写请求,因此我们需要使用一个READ_WRITE连接:
try
{;
// Open an HTTP connection with the Web server
httpConnection = (HttpConnection)
Connector.open(requestString, Connector.READ_WRITE);
// Set the request method to GET
httpConnection.setRequestMethod(HttpConnection.GET);
// Retrieve the response back from the JSP
dataInputStream =
new DataInputStream(httpConnection.openInputStream());
要得到一个HttpConnection实现,我们调用Connector.open()方法。该类包含有静态的方法,可根据连接字符串产生用作通信的相应接口。在这个例子中,我们要得到一个HttpConnection,因此我们将Connector.open()的响应放入HttpConnection接口。
一旦我们发出请求,我们就可以使用HttpConnection对象的openInputStream()方法,通过它可由JSP中得到结果的InputStream:
if(contentLength!=-1)
{;
for(int i = 0;I {;
if((inputChar = dataInputStream.read())!= -1)
{;
messagebuffer.append((char)inputChar);
};
};
}; else {;
// if the content-length is not available
while ((inputChar = dataInputStream.read()) != -1)
{;
messagebuffer.append((char) inputChar);
};
};
然后就可以读取该响应内容的长度,如果没有找到,你也可以一直读取它直到得到一个EOF或者出现一个错误的字符。每个由DataInputStream读取的字符都被加入到StringBuffer中。这个StringBuffer包含有一个XML表示的投票结果,它将被传送回调用的方法,然后再传送到convertXMLToVoteSummary()方法,如下所示:
private static VoteSummary convertXMLToVoteSummary(String xml)
{;
InputStreamReader insr = new InputStreamReader(
new ByteArrayInputStream(xml.getBytes() ) );
VoteSummary voteSummary = null;
Try
{;
voteSummary = XMLUtil.getVoteResults(insr);
}; catch (IOException ioe)
{;};
return voteSummary;
};
该方法将XML字符串转换为一个Java对象,这样我们就可以使用方法来得到数据,而不是分析数据。我们使用XMLUtil.getVoteResults()方法来做这个转换。在接触该方法前,我们先完成ResourceUtility对象。最后的一个方法是addEntry(),将新的投票传送到JSP。如上所述,为了效率,它再次使用backendComms()方法:
public static VoteSummary addEntry(Vote vote)
{;
StringBuffer requestString = new StringBuffer();
requestString.append(QUESTION + vote.toRequestString() );
String xml = backendComms(LOAD_URL, requestString.toString() );
return convertXMLToVoteSummary(xml);
};
XMLUtil
XMLUtil对象的作用是将由JSP接收的XML转换为一个VoteSummary对象,以便应用使用。要完成转换,它必须使用一个XML分析器来解析数据。为了减少MIDlet的整体大小,所以要使用一个轻量级的分析器以令MIDlet的整体大小最小化。在这个例子中,我使用的是Enhydra的kXML分析器。
以下就是这个对象中的getVoteResults()方法,我们来看看转换过程是如何进行的:
public static VoteSummary getVoteResults(InputStreamReader insr)
throws IOException
{;
XmlParser parser = new XmlParser (insr);
Document document = new Document();
document.parse( parser );
file://uncomment to see the document written to your console.
file://document.write( new XmlWriter( new OutputStreamWriter
( System.out) ) );
前几行是设置XmlParser和Document对象的。在创建这些对象后,就会调用Document.parse()方法,并且传送XmlParser作为参数。结果的文档包含有一个由JSP传送来的XML信息。如果你对验证信息的格式感兴趣,你可以将ocument.write调用前面的注释去掉,以看请文档的结构:
Element voteExampleElement = document.getElement("vote-example");
Element voteElement = voteExampleElement.getElement("votes");
String numVotes = getTextFromElement(voteElement, "number");
String avgVote = getTextFromElement(voteElement, "average");
在创建Document后,我们现在可使用DOM方法来得到Element对象并且获取其中的值。头两行是用来在XML文档中移动,以到达含有数据的节点。在得到voteElement节点后,我们就可以使用getTextFromElement()方法,这个方法执行多个命令从文档中得到文本节点,并且返回它的值:
Element choicesElement = voteElement.getElement("choices");
int childCount = choicesElement.getChildCount();
上面的两行代码用来取得在选择区域下的节点数目。使用childCount,你可以构造节点,这样就无需使用当前的投票数目。这样做是很重要的,因为以后你可能需要加入更多的投票。使用这些调用,你可以无需修改代码就做到这一点:
for (int i = 0; i < childCount; i++)
{;
if ( choicesElement.getType(i) == Xml.ELEMENT)
{;
choiceElement = choicesElement.getElement(i);
choicevalue = getTextFromElement(choiceElement,"value");
choiceName = getTextFromElement(choiceElement,"name");
choiceVotes = getTextFromElement(choiceElement,"number");
vote = new Vote(choicevalue, choiceName, choiceVotes);
vEntries.addElement(vote);
};
};
return new VoteSummary( numVotes, avgVote, vEntries);
这样我们就可以得到子元素的数目,然后可以遍历它们并且取得其中的投票信息。其中一些子节点是Element,而其它的是没有数据的Text节点。在这个例子中,我们仅关心Elements,因此我们要在循环中设置相应的条件。该循环将由选项Element中得到每个子Elements,并且构造一个Vote对象,该对象包含有值(用作计算)、名字和投票的数目。这些vote对象都被依次加入到Vector中。最后,这个方法初始化一个新的VoteSummary对象,该对象包含有以上三个信息。
private static String getTextFromElement(Element elementRoot,
String elementName)
{;
String returnText = elementRoot.getElement(elementName).getText();
return returnText;
};
我们使用getTextFromElement()方法来令代码的可读性更强。它的作用是深入树形结构一层,并且得到其中的Text节点信息。
voter.jsp
这个系统的最后一个元素是模拟后端系统的JSP。在这个例子中,我创建了一个简单的JSP,它使用类变量来跟踪投票计算。
具体的JSP见源代码。它只是跟踪投票并且返回以XML表示的数据。
最后的要点
这个例子讲解了MIDP和一个服务器端的组件如果通过HttpConnection来进行交互。通过发出一个请求,MIDP可以通过普通的HTTP GET/POST调用来与JSP组件通信。在这个例子中,调用返回XML信息。
使用kXML分析器,XML可以被有效地转换为一个对象,图形类就可以由该对象中获取数据。你也要注意到,在应用中的ChoiceGroup中并没有定义选项的数目,而是通过服务器端的组件动态设置。
与任何多层开发任务一样,要考虑如何有效地实现Model-View-Controller模型而避免创建多余的代码,这个想法在这个例子中也有体现,这个模型就是JSP。view就是显示全部数据信息的VoteResults对象。在这里的controller也是VoteResults对象,由于它实现了CommandListener接口。
通信
在这篇文章中,我们主要讨论了一个可产生HTTP请求的MIDP通信系统。这些请求可以是由使用标准协议的已知端口到任何使用私有协议的应用级协议。其中的API都可以很灵活地以一个很类似的方式处理这些请求。
在与远程机器交互的时候,如果你处于一个覆盖以外的区域(例如进入一个隧道时),这时会怎样呢?与WAP不同,在处于覆盖以外的区域时,具有MIDP功能的电话仍然可以继续运行它的应用。这个技术可以做到让用户使用离线的功能,并且在回到覆盖区域时,具有与在线应用同步的能力。例如一个基于MIDP的email应用:用户可以继续读取和回应已经下载到本地RMS datastore的email。在回到覆盖区域时,回复的信息可以发送到服务器,从而分发到不同的接收者。
当前发布的J2ME Wireless Toolkit版本并不支持HTTPS协议。不过,早些发布的开发者版本确实支持HTTPS。通过这些API的支持,你可以实现在Java电话上交易股票或者进行买卖。
相关推荐
Midp2.0 API 是Java ME(Micro Edition)平台的一部分,专为移动设备和嵌入式系统的应用程序开发设计。NokiaUI 是诺基亚公司针对Midp2.0 API 提供的一个扩展,它提供了丰富的用户界面组件和功能,使得开发者能够创建...
在Java ME(J2ME)平台上,MIDP(Mobile Information Device Profile)是为移动设备设计的一个精简版Java API。...通过分析和学习提供的源码,能够更直观地理解Game API的工作原理,从而提升游戏开发技能。
总结,Sony Ericsson MIDP文档API为开发者提供了在Sony Ericsson移动设备上开发Java应用程序的全面指南。通过理解并熟练运用这些API,开发者可以创造出功能强大、用户体验良好的移动应用,满足广大手机用户的多样化...
MIDP2.0 API,J2me必用,MIDP2.0 API,MIDP2.0 APIMIDP2.0 API
`midp2_gameapi.pdf` 文件很可能是详细的API文档,包含了这些类和接口的用法说明,而`readme.txt`可能包含关于如何使用这些资源的指南或者开发注意事项。`WAP之家.COM.url`可能是一个链接,指向有关MIDP开发或者移动...
8. **保存和加载游戏状态**: 可以利用MIDP 2.0提供的文件系统API保存游戏进度,方便用户继续游戏。 ### 示例代码 以下是一个简单的游戏循环示例: ```java public void run() { while (true) { if (!...
【描述】提到这个压缩包是“刚刚上传的rpg引擎的midpapi部分”,这表明Midpapi是RPG游戏引擎的一部分,可能包含了用于处理游戏逻辑、图形渲染、用户交互等功能的类和接口。"请勿用作商业用途,后果自负"的声明意味着...
本文将对 MIDP 2.0 的 Game API 进行详细介绍,并结合实际应用场景来帮助读者更好地理解和应用这一 API。 #### 二、MIDP 2.0 Game API 概述 MIDP 2.0 Game API 是 J2ME 平台上专门为移动游戏设计的一套 API。相较于...
javaME的核心API , java.io java.lang java.util javax.microedition.io javax.microedition.lcdui javax.microedition.lcdui.game javax.microedition.media javax.microedition.media.control javax....
MIDP(Mobile Information Device Profile)是Java ME的一个子集,主要用于移动设备和嵌入式系统的应用程序开发,特别是手机游戏和实用小工具。这份CHM(Compiled Help Manual)格式的文档提供了全面的API接口和类的...
不同? 在讨论移动游戏界面时,我们需考虑到与...综上所述,MIDP及其相关的API集为移动游戏开发者提供了一个起点,但随着技术的发展和用户期望的提高,开发者需要不断探索新技术和框架,以创造更加引人入胜的游戏体验。
总之,Java移动通信程序设计-J2ME MIDP涵盖了移动设备应用开发的基础知识,包括MIDP的结构、API使用、用户交互、网络通信和数据管理等,是开发者进入移动开发领域的入门教材。通过深入理解和实践这些概念,开发者...
MIDP 2.0的游戏API通过提供预构建的组件和优化机制,解决了这一问题。 ### 3. 游戏API关键类 游戏API的核心类位于`javax.microedition.lcdui.game`包下,主要包括: - **GameCanvas**:这是游戏API的基类,相较于...
7. **推送通知和蓝牙通信**:MIDP还支持PushRegistry,允许接收服务器端的推送消息,以及通过Bluetooth API实现设备间的无线通信。 8. **性能优化**:由于移动设备资源有限,优化代码以减少内存消耗和CPU使用是必要...
MIDP 2.0是J2ME针对移动设备提供的一套游戏开发框架,其中Game API提供了丰富的图形和动画处理功能。本文将详细介绍如何在Android环境中使用J2ME MIDP 2.0的Game API,特别是四个关键工具类:Layer、LayerManager、...
通过学习和分析这些代码,开发者可以深入理解MIDP的工作原理,掌握如何利用MIDP API构建实际的移动应用。这些示例代码对于初学者来说是非常宝贵的资源,能够帮助他们快速上手Java MIDP编程,并且为进阶开发打下坚实...