Due to the limited network protocols supported by wireless devices, they are limited to HTTP, Socket, UDP, and other protocols. Different manufacturers may also support other network protocols. However, MIDP 1.0 specifications stipulate that, HTTP is a required protocol, while other protocols are optional. Therefore, in order to port on different types of mobile phones, we try to use HTTP as the preferred protocol for network connection, so that we can reuse the server code. However, HTTP is a text-based protocol with low efficiency. Therefore, you must carefully consider the communication between the mobile phone and the server to Improve the efficiency as much as possible.
For MIDP applications, try:
1. When sending a request, append a User-Agent header and pass in the MIDP and its version number so that the server can identify the request from the MIDP application and send the corresponding response based on the version number.
2. When connecting to the server, a download progress bar is displayed so that you can see the download progress and interrupt the connection at any time.
3. Due to the slow connection speed of the wireless network, it is necessary to cache some data, which can be stored in the memory or in RMS.
For the server, the output response should be as follows:
1. explicitly set the Content-Length field so that the MIDP application can read the HTTP header and determine whether it can process the data of this Length. If it cannot, it can directly close the connection without continuing to read the HTTP body.
2. the server should not send HTML content, because the MIDP application is difficult to parse HTML. Although XML can be parsed, it consumes CPU and memory resources. Therefore, it should send compact binary content, use DataOutputStream to write data directly and set Content-Type to application/octet-stream.
3. Try not to redirect the URL. This will cause the MIDP application to connect to the server again, increasing the user's waiting time and network traffic.
4. if an exception occurs, for example, the requested resource is not found, or the authentication fails, the server usually sends an error page to the browser, which may also contain a user login Form. However, sending an error page to MIDP is meaningless. A 404 or 401 error should be sent directly, so that the MIDP application can directly read the response code of the HTTP header to obtain the error information without continuing to read the corresponding content.
5. Because the computing power of the server far exceeds that of the mobile client, the task of sending different responses to different client versions should be completed on the server. For example, determine the client version based on the User-Agent header sent by the client. In this way, clients of earlier versions can continue to be used without upgrading.
The MIDP network framework defines multiple Protocol network connections, but each vendor must implement HTTP connections and add required HTTPS connections in MIDP 2.0. Therefore, to ensure that the MIDP application can be transplanted on mobile platforms of different vendors, it is best to only use HTTP connections. Although HTTP is a text-based protocol with low efficiency, because it is widely used, the front-end of most server applications is based on HTTP Web pages, so the server code can be reused to the maximum extent. As long as the cache is well controlled, there is still a good speed.
SUN's MIDP Library provides the javax. microediton. io package, which can easily implement HTTP connections. However, due to the high network latency, you must put the online operations in a separate thread to avoid blocking the main thread and stop the response on the user interface. In fact, the MIDP runtime environment does not allow network connections in the main thread. Therefore, we must implement a flexible HTTP networking module that allows users to intuitively view the current upload and download progress and cancel the connection at any time.
A complete HTTP connection is: the user initiates a connection request through a command, and then the system gives a waiting screen prompt indicating that the connection is in progress. After the connection ends normally, go to the next screen and process the downloaded data. If an exception occurs during the connection process, a prompt will be sent to the user and returned to the previous screen. The user can cancel and return to the previous screen at any time while waiting.
We designed an HttpThread Thread class to connect to the server in the background. The HttpListener interface implements the Observer (Observer) mode so that HttpThread can prompt the Observer to start download, download ends, update progress bars, and so on. The HttpListener interface is as follows:
public interface HttpListener {
void onSetSize(int size);
void onFinish(byte[] data, int size);
void onProgress(int percent);
void onError(int code, String message);
}
The HttpListener interface is implemented on an HttpWaitUI screen inherited from the Form. It displays a progress bar and prompts, and allows you to interrupt the connection at any time:
public class HttpWaitUI extends Form implements CommandListener, HttpListener {
private Gauge gauge;
private Command cancel;
private HttpThread downloader;
private Displayable displayable;
public HttpWaitUI(String url, Displayable displayable) {
super("Connecting");
this.gauge = new Gauge("Progress", false, 100, 0);
this.cancel = new Command("Cancel", Command.CANCEL, 0);
append(gauge);
addCommand(cancel);
setCommandListener(this);
downloader = new HttpThread(url, this);
downloader.start();
}
public void commandAction(Command c, Displayable d) {
if(c==cancel) {
downloader.cancel();
ControllerMIDlet.goBack();
}
}
public void onFinish(byte[] buffer, int size) { … }
public void onError(int code, String message) { … }
public void onProgress(int percent) { … }
public void onSetSize(int size) { … }
}
HttpThread is the Thread class responsible for processing Http connections. It accepts a URL and HttpListener:
Class HttpThread extends Thread {
Private static final int MAX_LENGTH = 20*1024; // 20 K
Private boolean cancel = false;
Private String url;
Private byte [] buffer = null;
Private HttpListener listener;
Public HttpThread (String url, HttpListener listener ){
This. url = url;
This. listener = listener;
}
Public void cancel () {cancel = true ;}
GET content using GETLet's first discuss the simplest GET request. For a GET request, you only need to send a URL to the server and obtain the server response. Implement the following in the run () method of HttpThread:
Public void run (){
HttpConnection hc = null;
InputStream input = null;
Try {
Hc = (HttpConnection) Connector. open (url );
Hc. setRequestMethod (HttpConnection. GET); // The default value is GET.
Hc. setRequestProperty ("User-Agent", USER_AGENT );
// Get response code:
Int code = hc. getResponseCode ();
If (code! = HttpConnection. HTTP_ OK ){
Listener. onError (code, hc. getResponseMessage ());
Return;
}
// Get size:
Int size = (int) hc. getLength (); // return response size, or-1 if the size cannot be determined
Listener. onSetSize (size );
// Start read response:
Input = hc. openInputStream ();
Int percent = 0; // percentage
Int tmp_percent = 0;
Int index = 0; // buffer index
Int reads; // each byte
If (size! = (-1 ))
Buffer = new byte [size]; // The response size is known to determine the buffer size.
Else
Buffer = new byte [MAX_LENGTH]; // The response size is unknown. Set a fixed buffer size.
While (! Cancel ){
Int len = buffer. length-index;
Len = len> 128? 128: len;
Reads = input. read (buffer, index, len );
If (reads <= 0)
Break;
Index + = reads;
If (size> 0) {// Update Progress
Tmp_percent = index * 100/size;
If (tmp_percent! = Percent ){
Percent = tmp_percent;
Listener. onProgress (percent );
}
}
}
If (! Cancel & input. available ()> 0) // the buffer is full and cannot be read.
Listener. onError (601, "Buffer overflow .");
If (! Cancel ){
If (size! = (-1) & index! = Size)
Listener. onError (102, "Content-Length does not match .");
Else
Listener. onFinish (buffer, index );
}
}
Catch (IOException ioe ){
Listener. onError (101, "IOException:" + ioe. getMessage ());
}
Finally {// clear Resources
If (input! = Null)
Try {input. close ();} catch (IOException ioe ){}
If (hc! = Null)
Try {hc. close ();} catch (IOException ioe ){}
}
}
After the download is complete, HttpWaitUI obtains data from the server and transmits the data to the next screen for processing. HttpWaitUI must contain a reference to the screen and use a setData (DataInputStream input) the method allows the next screen to easily read data. Therefore, define a DataHandler interface:
public interface DataHandler {
void setData(DataInputStream input) throws IOException;
}
HttpWaitUI responds to the onFinish event of HttpThread and calls the setData method of the next screen to pass the data to it and displays the next screen:
public void onFinish(byte[] buffer, int size) {
byte[] data = buffer;
if(size!=buffer.length) {
data = new byte[size];
System.arraycopy(data, 0, buffer, 0, size);
}
DataInputStream input = null;
try {
input = new DataInputStream(new ByteArrayInputStream(data));
if(displayable instanceof DataHandler)
((DataHandler)displayable).setData(input);
else
System.err.println("[WARNING] Displayable object cannot handle data.");
ControllerMIDlet.replace(displayable);
}
catch(IOException ioe) { … }
}
Taking downloading a news piece as an example, a complete http get request process is as follows:
First, you want to read the specified news by clicking a command on a screen. In the commandAction event, we initialize HttpWaitUI and the NewsUI screen that displays data:
public void commandAction(Command c, Displayable d) {
HttpWaitUI wait = new HttpWaitUI("http://