📄 mar02_ericg.txt
字号:
log( "Receiving messages from server..." );
while( true ){
log( "Waiting..." );
SimpleMessage msg = hub.receive(
PULL_TIMEOUT );
if( msg == null ){
log( "Receive timed out, quitting" );
break;
}
log( "Received " + msg );
}
hub.stop();
hub.destroy();
}
}
This MIDlet is meant to be run from an emulator, not from a real
device. That's because it doesn't define a user interface.
Instead, it simply prints messages to the console.
There are many improvements you can make to this example. For
example, you can batch multiple messages together into a single
HTTP request/response cycle. Or you can add the ability to
register listeners which are asynchronously notified when there
are waiting messages. There are also commercial messaging
solutions available which are probably worth exploring. As you
can see, though, it doesn't really take that much code to build
a basic messaging framework.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
COMPRESSING XML FOR FASTER WIRELESS NETWORKING
An earlier J2ME Tech Tip showed how to parse XML documents in
CLDC-based profiles using XML parsers like kXML or NanoXML. (See
Parsing XML in CLDC-Based Profiles at
http://java.sun.com/jdc/J2METechTips/2001/tt0725.html#tip2.)
While XML is a useful, portable format for exchanging data
between different applications, it has some disadvantages. One of
these disadvantages is that it's very verbose. Remember, an XML
document is a text-based, human-readable document, so it's
verbose by design. Because current wireless networks are slow
(data throughput as low as 4KB per second is not unheard of),
passing XML documents between a server and a J2ME-enabled device
might be too slow to be workable. Also, parsing large documents
can easily cause out-of-memory errors on very constrained devices.
Encoding or transforming XML into a binary format is usually
a better solution.
Binary encodings of XML already exist. Perhaps the most relevant
encoding is WBXML, which is used in WAP to encode the decks of
Wireless Markup Language (WML) browser markup sent to cellphones.
The open-source kXML parser (see http://www.kxml.org) has
built-in support for generating and parsing WBXML.
WBXML works by replacing common tag and attribute names and/or
values with tokens. The exact set of tokens is configurable.
Using WBXML with the kXML parser is simply a matter of:
o Replacing org.kxml.parser.XmlParser with
org.kxml.wap.WbxmlParser
o Replacing org.kxml.io.XmlWriter with org.kxml.wap.WbxmlWriter
o Configuring the WbxmlParser and WbxmlWriter classes
appropriately before using them.
Here's a simple example. Say your J2ME application uses an XML
document to represent employee information. A typical employee
might be represented as:
<employee>
<firstname>Eric</firstname>
<lastname>Giguere</lastname>
<sex type="male"/>
<email valid="true" primary="true">
ericgiguere@ericgiguere.com
</email>
</employee>
This document is about 180 bytes long, depending on how many
whitespace characters you use. By replacing the tag and attribute
names and values with tokens you can reduce its length to less
than 70 bytes. All you do is define three tables. The first is
for tags:
public static final String tagTable[] = {
"employee",
"firstname",
"lastname",
"sex",
"email"
};
The second is for attribute names:
public static final String attrStartTable[] = {
"type",
"valid",
"primary"
};
The third is for attribute values:
public static final String attrValueTable[] = {
"true",
"false",
"male",
"female"
};
You get the best compression by making sure that all the tags and
attribute names (and as many values as possible) defined by your
XML Document Type Definition (DTD) are in the tables. Any values
not listed in the tables will still be correctly written out.
First create a WbxmlWriter object, setting the tables
appropriately (Note that the first argument to the "set" methods
must currently be hardcoded to 0.)
OutputStream out = ...; // a destination
WbxmlWriter writer = new WbxmlWriter( out );
writer.setTagTable( 0, tagTable );
writer.setAttrStartTable( 0, attrStartTable );
writer.setAttrValueTable( 0, attrValueTable );
Then write tags and attribute values as you normally would:
writer.startTag( "email" );
writer.attribute( "primary", "true" );
writer.attribute( "valid", "true" );
writer.write( "ericgiguere@ericgiguere.com" );
writer.endTag();
.... // etc. etc.
The WbxmlWriter class automatically encodes the tags, attributes,
and values for you, making for a much smaller XML document.
Parsing a WBXML document is just as simple. All you do is
initialize the WbxmlParser object with the same tables as the
WbxmlWriter:
InputStream in = ....; // an input source
WbxmlParser parser = new WbxmlParser( in );
parser.setTagTable( 0, tagTable );
parser.setAttrStartTable( 0, attrStartTable );
parser.setAttrValueTable( 0, attrValueTable );
ParseEvent event = parser.read();
..... // etc. etc.
As long as the writer and the parser are using the same set of
tables, you should have no problems shrinking your document
sizes.
Here's the code for a simple MIDlet (it has no user interface)
that writes out the same document using an XmlWriter and
a WbxmlWriter:
import java.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
import org.kxml.*;
import org.kxml.io.*;
import org.kxml.wap.*;
// A simple MIDlet that shows how to use WBXML
// encoding to "shrink" or "compress" XML documents.
public class XMLCompressTest extends MIDlet
implements CommandListener {
private Display display;
public static final Command exitCommand =
new Command( "Exit",
Command.EXIT, 1 );
public XMLCompressTest(){
}
public void commandAction( Command c,
Displayable d ){
if( c == exitCommand ){
exitMIDlet();
}
}
protected void destroyApp( boolean unconditional )
throws MIDletStateChangeException {
exitMIDlet();
}
public void exitMIDlet(){
notifyDestroyed();
}
public Display getDisplay(){ return display; }
protected void initMIDlet(){
try {
testXML();
}
catch( Exception e ){
System.err.println( "Exception " + e );
}
exitMIDlet();
}
protected void pauseApp(){
}
protected void startApp()
throws MIDletStateChangeException {
if( display == null ){
display = Display.getDisplay( this );
initMIDlet();
}
}
private void log( String str ){
System.out.println( str );
}
// Write an XML document to the given writer
private void writeXML( AbstractXmlWriter writer )
throws IOException {
writer.startTag( "employee" );
writer.startTag( "firstname" );
writer.write( "Eric" );
writer.endTag();
writer.startTag( "lastname" );
writer.write( "Giguere" );
writer.endTag();
writer.startTag( "sex" );
writer.attribute( "type", "male" );
writer.endTag();
writer.startTag( "email" );
writer.attribute( "valid", "true" );
writer.attribute( "primary", "true" );
writer.write( "ericgiguere@ericgiguere.com" );
writer.endTag();
writer.endTag();
writer.close();
}
// Table for the tags in our DTD
private static final String tagTable[] = {
"employee",
"firstname",
"lastname",
"sex",
"email"
};
// Table for the attribute names in our DTD
private static final String attrStartTable[] = {
"type",
"valid",
"primary",
};
// Table for the attribute values in our DTD
private static final String attrValueTable[] = {
"true",
"false",
"male",
"female"
};
// Show the difference in writing out the same
// document using plain XML and then WBXML.
private void testXML() throws IOException {
log(
"Writing uncompressed XML to a string..." );
ByteArrayOutputStream out =
new ByteArrayOutputStream();
XmlWriter xw = new XmlWriter(
new OutputStreamWriter( out ) );
writeXML( xw );
String str = new String( out.toByteArray() );
log( "String length is " + str.length() );
log( "String value is" );
log( str );
log( "Writing compressed XML to a string..." );
out = new ByteArrayOutputStream();
WbxmlWriter bxw = new WbxmlWriter( out );
bxw.setTagTable( 0, tagTable );
bxw.setAttrStartTable( 0, attrStartTable );
bxw.setAttrValueTable( 0, attrValueTable );
writeXML( bxw );
str = new String( out.toByteArray() );
log( "String length is " + str.length() );
log( "String value is" );
log( str );
log( "Done." );
}
}
Of course, you can't use a binary encoding like WBXML without
support from the server. The server must generate and accept XML
documents in binary form, not the usual text form. This appears
to limit who the client can talk to. But realistically, the
client only talks to a single server, so it's not such a
limitation. If access to other servers is required, the primary
server can act (with a bit of coding) as a proxy on the client's
behalf.
For really simple formats you can probably even eliminate using
the WBXML format. If the client talks to a Java-based server
application, it's very easy to encode all kinds of information in
a portable and efficient manner using the DataInputStream and
DataOutputStream classes. See the Tech Tip "Client-Server
Communication over HTTP using MIDP and Servlets" for details
(http://java.sun.com/jdc/J2METechTips/2001/tt0820.html#tip2).
. . . . . . . . . . . . . . . . . . . . . . .
IMPORTANT: Please read our Terms of Use, Privacy, and Licensing
policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html
* FEEDBACK
Comments? Send your feedback on the J2ME Tech Tips to:
jdc-webmaster@sun.com
* SUBSCRIBE/UNSUBSCRIBE
- To subscribe, go to the subscriptions page,
(http://developer.java.sun.com/subscription/), choose
the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page,
(http://developer.java.sun.com/subscription/), uncheck the
appropriate checkbox, and click "Update".
- To use our one-click unsubscribe facility, see the link at
the end of this email:
- ARCHIVES
You'll find the J2ME Tech Tips archives at:
http://java.sun.com/jdc/J2METechTips/index.html
- COPYRIGHT
Copyright 2002 Sun Microsystems, Inc. All rights reserved.
901 San Antonio Road, Palo Alto, California 94303 USA.
This document is protected by copyright. For more information, see:
http://java.sun.com/jdc/copyright.html
J2ME Tech Tips
March 25, 2002
Sun, Sun Microsystems, Java, Java Developer Connection, and J2ME
are trademarks or registered trademarks of Sun Microsystems,
Inc. in the United States and other countries.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -