Wednesday, August 11, 2010

Basic Usage of LWUIT4IO

Last week I wrote about LWUIT4IO but didn't really explain how to utilize it properly and what makes it completely different from just using the GCF (Generic Connection Framework: Connector.open etc.).

Normally in MIDP you would just connect to the internet using Connector.open(String, ?) and get a connection object or a stream. The process seems simple enough but there are lots of hidden caveats in this process. For instance you would need to handle errors in case they happen (and they often do on a mobile device), in which case you need to show an error dialog (which is usually very uniform for all the connections you have in your application.
You also need to conduct the networking in a separate thread that is neither the LWUIT nor the default MIDP thread since these threads will block the UI from updating. After finishing every operation or in case of an exception it is critical in MIDP to cleanup all the connections/streams appropriately. Developers often forget to do this because the GC often removes that need, but with the GCF it is often critical to invoke close() otherwise native resources won't be freed and might cause issues on some devices (very common issue in feature phones).

LWUIT4IO tries to solve all of these by hiding the entire process of networking behind a component API, e.g. to connect to a URL and fetch its content in LWUIT4IO one could do just:
NetworkManager.getInstance().addToQueue(myRequest);

You do first need to initialize LWUIT4IO by invoking (similar to the need of invoking Display.init once):
NetworkManager.getInstance().start();

The request object is a callback class that includes the URL/arguments and request method (get/post). The network thread will perform the connection and invoke the proper callback methods within the request object e.g.:
ConnectionRequest myRequest = new ConnectionRequest();
myRequest.setUrl("http://mysite.com/");
myRequest.addArg("arg", "value");
addResponseListener(new ActionListener() {
public void actionEvent(ActionEvent ev) {
NetworkEvent n = (NetworkEvent)ev;

// gets the data from the server as a byte array...
byte[] data = (byte[])n.getMetaData();
}
});

Alternatively one can override the code to read/write the request values e.g.:
ConnectionRequest myRequest = new ConnectionRequest() {
protected void readResponse(InputStream input) throws IOException {
// read from the input stream...
}
};

Besides the advantages of the more generic code, the true advantages you gain in using this approach is quite remarkable:
  • You don't need to write threading code - LWUIT callbacks (e.g. actionPerformed) are on the LWUIT EDT seamlessly. Everything else automatically goes to the network thread...
  • Exceptions are caught and handled without any need to do anything.
  • You don't need to close streams or connections ever!
  • All streams are buffered so you don't need to worry abound efficiency of reading from a data input stream.
  • You can utilize inheritance and reuse code far more extensively
  • Cookies, redirects work pretty much like you would expect without any additional code.

0 comments:

Post a Comment