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.

10 comments:

  1. This is a great addition. I've had the pleasure to use the package, and have already found few bugs, and what looks like an Unexpected End of Stream in Util.readInputStream() when connecting to HTTP/1.1 Keep-Alive servers.

    I'm wondering where is the Issue Tracker for LWUIT4IO?

    TIA.

    ReplyDelete
  2. LWUIT4IO looks really great. Networking, let alone webservices, really is a pain with J2ME.

    When testing with the IODemo application runs fine but when trying in a new project i get following exception:

    java.lang.SecurityException: Application not authorized to access the restricted API

    It probably has todo with the Nokia API...

    After comparing project settings I don't really see what's wrong, any advice?

    Thanks!

    ReplyDelete
  3. @oriental: Thanks for your response!

    Another question: Is it possible the use PUT and DELETE?

    If not supported now, any suggestions what the best solution would be?

    Thanks! ;-)

    ReplyDelete
  4. Note: The security error I mentioned before only occurs when using the DefaultFxTouchPhone emulator within the J2ME SDK 3.0.

    Strange!

    ReplyDelete
  5. @Pablo:
    1. CLDC has timeouts but you can't define how long they take. So eventually the timeout will naturally occur. Potentially they won't work and your application will slowly run out of resources. But it will still work.

    2. We have one thread. Threads are abandoned only on a timeout.

    3. SOAP is too complex for now.

    4. Yes, the phones support it.

    5. No. Since this will add encryption to the code which will introduce elaborate export restriction licensing...


    @Oriental Use the standard LWUIT issue tracker for all LWUIT4IO issues.

    @Sander: you usually need to specify a trusted domain/permissions for the application.
    Right now we don't support PUT/DELETE, if you have a good use case for PUT/DELETE then feel free to open a RFE in the LWUIT issue tracker.

    ReplyDelete
  6. Hello
    I am downloading yahooAnswer project and i am facing problem to compile the source package so please help me. If you have jar and jad file then mail me please as soon as earlier.

    ReplyDelete
  7. Where i can find the LWUIT4IO binaries? Have I to build them with NetBeans? Plain ant build from {SVN}\trunk\IO\build.xml seems not working. It's failing during pre-load-properties task because I don't have NetBeans installed.
    Thank you

    ReplyDelete
  8. LWUIT browser now supports LWUIT4IO in SVN.
    There are binaries in the resource editor generated project, but there are no official binaries.
    You can build the project without netbeans but it requires some work in editing the properties files to point at the right things. Haven't tried it though.

    ReplyDelete
  9. Hi everybody,

    Perhaps it's too late to asking this: How can I detect when the mobile data and Wifi are switched off? I got an exeption when the next line is executed:

    NetworkManager.getInstance().addToQueue(myRequest);

    I tried the classic try{...}catch(Exception e){...}
    but doesn't work. Obviously the error appears because there is no mobile data or wifi activated, I want to take control of that behaviour. I'm developing an app for Nokia S40 Full touch.

    Best regards,

    ReplyDelete
  10. Got it!

    The answer it's simple, there are two roads:

    1.- Just create a class extending from the ConnectionRequest and overriding the handleIOException method and I took control of the exeption and the dialog message.
    2.- Overriding the method directly:

    ConnectionRequest myRequest = new ConnectionRequest() {
    protected void handleIOException(IOException err) {
    // All the stuff
    }
    };

    That's all!

    Maybe this is useful for somebody else.

    Regards

    ReplyDelete