⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 aug01_ericg.txt

📁 TechTips j2me的常用技巧. 网络功能
💻 TXT
📖 第 1 页 / 共 2 页
字号:

 J 2 M E    T  E  C  H    T  I  P  S

                      TIPS, TECHNIQUES, AND SAMPLE CODE


WELCOME to the Java Developer Connection(sm) (JDC)
Java(tm) 2 Platform, Micro Edition (J2ME(tm)) 
Tech Tips, for August 20, 2001. This issue covers:

     * Building Splash Screens for MIDlets
     * Client-Server Communication over HTTP using MIDP and 
       Servlets
         
The J2ME Tech Tips are written by Eric Giguere
(http://www.ericgiguere.com), an engineer at iAnywhere 
Solutions, inc. Eric is the author of the book "Java 2 Micro
Edition: Professional Developer's Guide" and co-author of the 
upcoming "Mobile Information Device Profile for Java 2 Micro 
Edition," both books in John Wiley & Sons' Professional 
Developer's Guide series.

You can view this issue of the J2ME Tech Tips on the Web at
http://java.sun.com/jdc/J2METechTips/2001/tt0820.html

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
BUILDING SPLASH SCREENS FOR MIDLETS

A splash screen is an informational screen that presents the name 
and version of an application, along with any necessary legal
information such as the copyright and trademark notices. It's 
something you might want your MIDlets to display on startup. 
Adding a splash screen to a MIDlet is easy to do, but there are 
a few things to watch out for.

The simplest way to build a splash screen is to use an Alert. 
Alerts, which were discussed in detail in the April 16, 2001
J2ME Tech Tip titled "An Introduction to the High-Level User 
Interface API: Alerts and Tickers" (see 
http://java.sun.com/developer/J2METechTips/20001/tt0416.html#tip2),
are part of the Mobile Information Device Profile (MIDP) 
high-level user interface API. An alert displays a message and an 
optional image for a set period of time or until the user 
explicitly dismisses the alert. So building a splash screen is 
simply a matter of building and displaying an alert, as done by 
the following method:

public void showSplashScreen( 
                         Display d, Displayable next ){
    Image logo = null;
    
    try {
        logo = Image.createImage( "/images/logo.png" );
    }
    catch( IOException e ){
    }
    
    Alert a = new Alert( "Time Tracker", 
           "Copyright 2001 by Nobody, Inc.",
            logo, null ); 
    a.setTimeout( Alert.FOREVER );
    display.setCurrent( a, next );
}

An alert might not be flexible enough for your needs, however. 
To dismiss the splash screen with any key or to display a simple 
animation, you'll need to use a Canvas for your splash screen. 
For example, you could define a simple splash screen like this:

import java.util.*;
import javax.microedition.lcdui.*;

public class SplashScreen extends Canvas {
    private Display     display;
    private Displayable next;
    private Timer       timer = new Timer();

    public SplashScreen( 
                   Display display, Displayable next ){
        this.display = display;
        this.next    = next;

        display.setCurrent( this );
    }

    protected void keyPressed( int keyCode ){
        dismiss();
    }

    protected void paint( Graphics g ){
        // do your drawing here
    }

    protected void pointerPressed( int x, int y ){
        dismiss();
    }

    protected void showNotify(){
        timer.schedule( new CountDown(), 5000 );
    }

    private void dismiss(){
        timer.cancel();
        display.setCurrent( next );
    }

    private class CountDown extends TimerTask {
        public void run(){
            dismiss();
        }
    }
}

To display this splash screen, simply create an instance of it.
When you create the instance, you pass to it the MIDlet's 
Display object; you also pass to it the screen to activate after 
the splash screen is dismissed:

public void showSplashScreen( 
                   Display display, Displayable next ){
    new SplashScreen( display, next );
}

The splash screen is dismissed when the user presses any key or 
presses on the screen (if the device supports a pointing device).  
If neither event occurs, the screen is automatically dismissed 
five seconds after it is first displayed.

When should you display a splash screen? Your first thought might 
be to make its activation the last line of the MIDlet's startApp 
method. Remember, though, that the startApp method can be called 
more than once for the same MIDlet instance. The constructor is 
not a good place to activate a splash screen because the MIDP 
specification does not guarantee that the MIDlet's Display object 
(required to display any kind of screen or alert) is initialized 
yet. So the startApp method is indeed the place to call a splash 
screen, but only once. The startApp method is also where you can 
safely obtain the MIDlet's Display object, so combine the two
tasks as in the following MIDlet:

import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;

public class MyMIDlet extends MIDlet
                      implements CommandListener {

    private Display display;
    private Command exitCommand = new Command( 
                             "Exit", Command.EXIT, 1 );

    public MyMIDlet(){
    }

    protected void destroyApp( boolean unconditional )
                    throws MIDletStateChangeException {
        exitMIDlet();
    }

    protected void pauseApp(){
    }

    protected void startApp() 
                    throws MIDletStateChangeException {
        if( display == null ){ // first time called...
            initMIDlet();
        }
    }

    private void initMIDlet(){
        display = Display.getDisplay( this );
        new SplashScreen( display, new TrivialForm() );
    }

    public void exitMIDlet(){
        notifyDestroyed();
    }

    public void commandAction( 
                            Command c, Displayable d ){
        exitMIDlet();
    }

    // A trivial UI screen

    class TrivialForm extends Form {
        TrivialForm(){
            super( "MyMIDlet" );
            addCommand( exitCommand );
            setCommandListener( MyMIDlet.this );
        }
    }
}

It isn't usually necessary to display a splash screen each time 
a MIDlet is invoked. Ideally, you should display a splash screen 
the first time the user runs the MIDlet, but not again. To do
this, you need to use the Record Management System (RMS) classes 
to store an indication of whether the application has been run. 
(The basics of the RMS were covered in the February 20, 2001 J2ME 
Tech Tip "Record Management System Basics," see
http://java.sun.com/jdc/J2METechTips/2001/tt0220.html#tip2.)
This approach could be as simple as testing for the existence of 
a particular record store (which could even be shared among all 
the MIDlets in the same MIDlet suite). You display the splash 
screen only if the record store doesn't exist. After you display 
the splash screen, you create an empty record store to indicate 
that the splash screen has been shown. 

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CLIENT-SERVER COMMUNICATION OVER HTTP USING MIDP AND SERVLETS

Many, if not most, Mobile Information Device Profile (MIDP)
applications have a server-side piece to them. In other words, 
a client-server paradigm is used to offload complicated work from 
the limited capabilities of the MIDP device to the more capable 
server environment. Because the MIDP 1.0 specification only 
mandates support for HTTP, all client-server communication must 
be done through an HTTP gateway, of which a web server is one 
example (however vendors are free to add support for different 
communication protocols). This Tech Tip looks at how MIDlets can 
communicate with servlets or JavaServer Pages(tm) (JSP(tm)) 
running on a web server. The same techniques can also be used to 
communicate with server applications written in other languages 
such as Perl, but using the Java programming language on both
ends of the communication makes coding simpler.

The first step is to understand how MIDlets can use HTTP to talk 
to a web server using the HttpConnection class. This was covered 
in the December 18, 2000 J2ME Tech Tip, "Making HTTP Connections 
with MIDP" 
(http://java.sun.com/jdc/J2METechTips/2000/tt1218.html#tip2).
If you read the Tech Tip, pay close attention to the 
HttpConnectionHelper class developed in the tip.

The second step is to configure your web server to support 
servlets, JSPs, or both. This is beyond the scope of this Tech 
Tip, but there are several web servers or web server extensions, 
both free and commercial, that you can use. For example, you
can use the Tomcat servlet engine from the Apache Software 
Foundation. Tomcat is a free, open-source web server that is 
downloadable from the Jakarta Project binary download site
(http://jakarta.apache.org/site/binindex.html). A good place to 
start looking for web servers is the Java Servlet Technology page
(http://java.sun.com/products/servlet/) and the JavaServer 
Pages(tm) Technology page (http://java.sun.com/products/jsp/). 
Note that if you run your MIDlets in an emulator, a local web 
server with servlet or JSP support is all you need. If you want 
to run MIDlets on real devices, however, the web server must be 
accessible from the Internet, which might require configuration 
help from your IT department.

After you complete these basic steps, you're ready to try your 
first client-server communication. Use the HTTP POST method in 
place of the GET method to transfer arbitrary data from the 
client to the server. With GET, the only way to pass data is 
using encoded text as part of the request URL. POST is more 
flexible because it allows you to specify a specific format for 
the data (including binary) and it doesn't have the length 
restrictions of the GET method.

To make a POST request using the MIDP's HttpConnection class, 
you first obtain the HttpConnection object and then call its 
setRequestMethod method:

import java.io.*;
import javax.microedition.io.*;

try {
    String url = ....; // a URL
    HttpConnection conn = (HttpConnection) 
                              Connector.open( url );
    conn.setRequestMethod( HttpConnection.POST );
    ..... // other code here
}
catch( IOException ioe ){
    // handle I/O errors
} 

Remember to call setRequestMethod before attempting to obtain 
any input or output streams, otherwise the call will have no 
effect.

After setting the request method, you should also set any 
appropriate HTTP headers. The MIDP Specification requires that 
you set the User-Agent and Content-Language headers:

conn.setRequestProperty( "User-Agent", 
           "Profile/MIDP-1.0 Configuration/CLDC-1.0" );
conn.setRequestProperty( "Content-Language", "en-US" );
    
You should also consider setting the Accept and Connection 
headers:

conn.setRequestProperty( "Accept", 
                          "application/octet-stream" );
conn.setRequestProperty( "Connection", 
                                 "close" ); // optional
 
The Accept header tells the web server what kind of data the 
client will accept. Use the MIME type that best describes the 
data you expect to receive.

The Connection header controls the "keep alive" feature of an 
HTTP connection; this feature lets the client and the server 
reuse the same connection for multiple requests. If you plan 
to make many requests to the same server over a short period of 
time, you might get better performance by not setting the 
Connection header. If you don't set the Connection header, the
state defaults to keep alive. Otherwise, you should set the
Connection header value to "close" (as above) to ensure that the 
connection is terminated after the server sends its response.

The Connection header is particularly important because of its 
close association with the Content-Length header. The 
Content-Length header lists the size (in bytes) of the request or 
response body. A valid Content-Length header is necessary for 
keep alive to work -- it's a requirement of the HTTP 1.1 
protocol. If the Content-Length header is missing from the 
request, the server won't know how many bytes of data to read, 
and the client will have a similar problem if it's missing from 
the response. An incorrect value can also cause problems. This is 
why during development it's often a good idea to turn off keep 
alive; this avoids having either end of the conversation block, 
waiting for non-existent data to be received. You can turn keep 
alive back on once you're sure the data is being sent and 
received correctly.

Now you're ready to send the data along with the POST request.  
Assuming that the data is in binary format, this is what you do:

byte[] data = ....; // the data to send

conn.setRequestProperty( 
   "Content-Length", Integer.toString( data.length ) );

OutputStream os = conn.openOutputStream();
os.write( data );
os.close();

What data format should you use for your communication with the 
server? It's really up to you. You could send an XML document, 
but XML is very verbose. If the server is written in the Java
programming language, why not use the encoding and decoding 
capabilities of DataOutputStream and DataInputStream? In other 
words:

// Example of sending some structured data to the server...
DataOutputStream os = new DataOutputStream( 
                             conn.openOutputStream() );
os.writeBoolean( true );
os.writeUTF( "This is a string..." );
os.writeInt( 5 );
os.close();

After you close the output stream, an HTTP POST request is formed
and sent to the web server. The MIDlet should next call 
getResponseCode to obtain the servlet's response code to check
for a valid response. Normally, this means checking that the 
response code is HttpConnection.HTTP_OK:

int rc = conn.getResponseCode();
if( rc == HttpConnection.HTTP_OK ){
    // safe to process the response
} else {
    // deal with errors, warnings, redirections, etc.
}

A response code other than HTTP_OK is not necessarily an error.  
The web server might redirect you to another URL, for example, in 
which case you should resend the data to the new URL (the 
HttpConnectionHelper class handles this for you automatically).  

Processing the response data is a matter of opening an input 
stream to read the response body. If structured data is being 
sent back, do the following:

DataInputStream in = new DataInputStream( 
                              conn.openInputStream() );
String msg = in.readUTF();
..... // etc. etc., read other data
in.close();

Alternatively, if the data being sent back is something like an 
image, you should check the length of the response to see how 
much data is being sent. If the length is not -1, allocate a byte 
array of that size and read the data into the byte array:

byte[]      data;
int         len = conn.getLength();
InputStream in = conn.openInputStream();

if( len != -1 ){ 
    int total = 0;
    data = new byte[len];
    
    while( total < len ){
        total += in.read( data, total, len - total );
    }
} else {
    ByteArrayOutputStream tmp = 
                          new ByteArrayOutputStream();
    int ch;
    
    while( ( ch = in.read() ) != -1 ){
        tmp.write( ch );
    }
    
    data = tmp.toByteArray();
}

in.close();

Be sure to respect the response body length. If you try to read 
more bytes than were sent, your application will block until the 
server decides to timeout the connection. Also, you must always 
be prepared to handle the case where the length is not set.

On the server side, things are fairly simple. In a way similar
to how the MIDlet processes the response, the servlet gets the
length of the request body and opens an input stream to process 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -