Sunday, December 5, 2010

Two User Interface handlers for SL4A WebView

I'm currently working on further projects of using WebView in SL4A to create a user interface. By using the two handler classes created for the SMS Merger, the communication to/from Python/Javascript is really simplified. The rest of the code is just HTML+Javascript to create the User Interface, Python to handle the background tasks.

Python handler


How it works


The UI Handler will be listening (waiting) for an event that will be posted by the Javascript side. This event will include data which is a JSON encoded dict. The handler will then dispatch to the function corresponding to the "task" key in the data dict. Once the task has done its job, the handler will post a response event which will be caught by the Javascript side.

Init and dispatch

The UIHandler class is actually never used directly. Each script needs to extend it into another class (e.g. class CallUIHandler(UIHandler)) and then loop on the wait function. The dispatch dict of the UIHandler is empty, meaning that any call to a given task will lead nowhere. The dispatch dict of the extended class (CallUIHandler) must "point" from a task string (e.g. "callme") to a function of the CallUIHandler (e.g. dispatch = {"callme":self.callme}). The callme method is then defined in the CallUIHandler (e.g. def callme( self, data ): ).

Receiving event and responding

While looping on the wait() function, the handler is waiting for an event (by default "python"). Data from the event is directly decoded from JSON into a python dict so the data is available to each of the task functions. The task function must return the data it wishes to pass back to the javascript side - that data will be JSON encoded before passing it to the response event, which means that it should be an dict/list/tuple (otherwise JSON encoding might fail).

Miscellaneous stuff

There are a startLoad(title,message) and a stopLoad() functions available, that are simple ways of showing/hiding an Android spinner dialog.
There is a default log function that may be overridden in the extended class.
The 0.2 second thing, is due to a glitch in the droid.waitForEvent function: If Python catches an event and posts its response too quickly, the Javascript side will miss it. So we make sure that our processing takes at least 0.2 seconds. (value was found by trial and error)

Sample extended UIHandler

This could be an example of extended UIHandler.

Javascript UIHandler


How it works

The javascript side basically works the same as the python side, except that it is usually the active side, the side that posts an event and waits for a response.

post and postAndWait

These are the functions used to send an event to the python handler. post simply sends the event including the data. postAndWait waits for a response (Javascript is blocked until then).


A utility function to show an alert dialog including title and message

startLoad and stopLoad

Utility functions used to show/hide a spinner dialog

delay thingy

Again, as on the Python side, there will be a problem if events are received/posted too quickly. Therefore the UIHandler has a property called "last" that records the microtime() value of the last event post. If we try too fast, it will delay the next post.


Note that a global variable droid is used which needs to be defined earlier as droid = Android();

Sample of application

This could be the HTML side:


  1. You did a great job. Thumbs up! (>^_^)>

    (im gonna bookmark this on my phone =} )

  2. This is the best SL4A info I've found anywhere - good job!

  3. GREAT JOB! Really nice! But I got to ask. How did you close the webview? I saw that you're looking for a workarround. Me too. Did you got it?