Dear reader of Juri's TechBlog,
I moved my blog to a new domain and a new hosting solution as well. I'm now blogging on juristr.com.

ExecutableTask pattern to tackle J2ME multithreading

Programming on the mobile device is quite different to more common environments like web or client-server desktop applications. Although mobile devices become always more and more powerful (i.e. like iPhone's OS and Android) one has still to consider issues like limited memory and I/O devices. Take for instance a look at the Android best practices.

When programming on J2ME for the CLDC these kind of things are key issues that have to be considered. There are a number of best practices around, one being the advise to place "heavy" computations in a separate thread in order to not block the J2ME system thread. That implies that you'll have to deal with a lot of threads that need to be handled. Keeping track of the execution of these threads can often become quite complicated.
Therefore - in my last J2ME project - I've created what I called the "Executable Task pattern" in order to handle these situations more easily. Actually it's not a pattern per sé but more like a variant of an Observer and Command pattern. A similar approach is used for defining the Java Swing event handlers for button clicks etc.

The "Executable Task" is composed of two objects.

public abstract class TaskProcessListener {
 /**
  * Gets invoked when the {@link ExecutableTask} finishes processing
  * @param result the resulting object from the computation
  */
 public abstract void onSuccess(Object result);
 
 /**
  * Gets invoked when an error occurs during processing
  * @param status the status message containing information about the error
  */
 public abstract void onError(String status);
}

This is the abstract class that defines the abstract methods that have to be implemented. This "TaskProcessListener" is used by the 2nd class, the "ExecutableTask".
public abstract class ExecutableTask implements Runnable {
 protected TaskProcessListener listener;
 
 public ExecutableTask(){ 
 }
 
 public void run(){
  //initializations prior the execution of the task itself
 }
 
 public ExecutableTask(TaskProcessListener listener){ 
  this.listener = listener;
 }

 protected void notifyTaskFinished(Object result){
  this.listener.onSuccess(result);
 }
 
 protected void notifyError(String statusMessage){
  this.listener.onError(statusMessage);
 }

 public TaskProcessListener getListener() {
  return listener;
 }

 public void setListener(TaskProcessListener listener) {
  this.listener = listener;
 }
}

This is the main class, but still quite simple, isn't it? There isn't much to explain here, just a couple of class members and getters and setters. Note however that the class is declared abstract and that it inherits from "Runnable", meaning that it can be executed within a thread.
Now comes the interesting part. When you actually have an operation that needs to run within his own thread (i.e. a network access) you inherit from the ExecutableTask class instead of Runnable as you would usually do. Consider for instance the simple code for downloading an Image from the web by using an HttpConnection which I've posted a couple of days ago. You would code that as follows:
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import javax.microedition.lcdui.Image;

public class ImageLoaderTask extends ExecutableTask {
 private String imageUrl;
 
 public ImageLoaderTask(String imageUrl){
  this.imageUrl = imageUrl;
 }

 public void run() {
  HttpConnection connection;
  try {
   connection = (HttpConnection) Connector.open(this.imageUrl);
   connection.setRequestMethod(HttpConnection.GET);
   
   Image loadedImg = Image.createImage(connection.openInputStream());
   notifyTaskFinished(loadedImg);
  } catch (Exception e) {
   notifyError(e.getMessage());
  }
 }
 
}

The instantiation of the ImageLoaderTask is then done by writing...
ImageLoaderTask imageLoadTask = new ImageLoaderTask(imageUrlField.getString());
imageLoadTask.setListener(new TaskProcessListener(){

 public void onError(String status) {
  //alert the user about the problem
 }

 public void onSuccess(Object result) {
  //do something with the result
 }
 
});
...again really simple. You can use the "onError(...)" for notifying the user about some problem during the execution of the task and the "onSuccess(...)" for processing a successful outcome.
The following Form demonstrates the usage of the ImageLoaderTask:
import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.AlertType;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.TextField;
import javax.microedition.lcdui.Ticker;

public class ImageForm extends Form implements CommandListener {
 private TextField imageUrlField;
 private Command loadImage;
 private Display display;

 public ImageForm(Display display) {
  super("Image Viewer");
  init();
  this.display = display;
 }

 private void init() {
  imageUrlField = new TextField("Image URL", "", 999, TextField.URL);
  this.append(imageUrlField);

  loadImage = new Command("Load Image", Command.SCREEN, 1);
  this.addCommand(loadImage);

  this.setCommandListener(this);
 }

 public void showLoadedImage(Image image) {
  if(this.size() == 2)
   this.delete(1);
  this.imageUrlField.setString("");
  this.append(image);
  this.setTicker(null);
 }

 public void commandAction(Command c, Displayable d) {
  if (c == loadImage) {
   downloadImage();
  }
 }
 
 private void showMessage(String message){
  this.setTicker(new Ticker(message));
 }
 
 private void stopMessage(){
  this.setTicker(null);
 }
 
 private void downloadImage(){
  showMessage("loading image");
  
  ImageLoaderTask imageLoadTask = new ImageLoaderTask(imageUrlField.getString());
  imageLoadTask.setListener(new TaskProcessListener(){
  
   public void onError(String status) {
    stopMessage();
    
    //show an alert notifying about the problem
    Alert alert = new Alert("Error", "Error when loading image " + status, null, AlertType.ERROR);
    alert.setTimeout(Alert.FOREVER);
    display.setCurrent(alert);
   }
  
   public void onSuccess(Object result) {
    showLoadedImage((Image)result);
   }
   
  });
  
  Thread t = new Thread(imageLoadTask);
  t.start();
 }

}

Posts you might also be interested in..

Credits: Hoctro | Jack Book

1 Comments:

masc said...

Hi Juri,

that's a very good approach for JavaME! I'll testing it soon.

bye
Marco

Post a Comment