views:

519

answers:

5

I'm working on a J2ME Bluetooth application, and one of the classes searches for other Bluetooth devices. It does this in another thread, so the GUI doesn't freeze up.

The problem I have is how to pass messages to the thread. I can ask it to search, or cancel searching, and it can tell the GUI it has found some other devices. Currently I use notify and wait, but that seems like a hack. What I really want is some way of calling notify with a parameter, for example what I want it to do. Is there any way to do this?

A: 

As of Java 1.5 there is really no need to use the wait/notify methods in user-code any more. You should use the java.util.concurrency package instead. I'd probably use a BlockingQueue type which allow the background thread to block on the queue until a message has arrived (or a timeout occurs).

EDIT: I didn't realise that java.util.concurrency wasn't available for J2ME, but I'll leave the answer in place since it might be useful to someone else.

JesperE
Unfortunately it is not available in J2ME...
Marius
Clearly stating J2ME as target platform. So this is of no use.
zedoo
Right you are. Note to self: read the *entire* question before replying.
JesperE
A: 

Looks like Observer pattern can be used here. Check if its possible in j2me.

Bhushan
A: 

The standard idiom for this in Java SE is to use a SwingWorker, which will make a callback to the done() method on the Event Dispatch thread after the work is completed on the background thread (or an Exception has been thrown). Not sure if this exists for J2ME though.

Check out the tutorial here.

Adamski
+1  A: 

You'll have to implement you're own blocking queue, this is actually a producer-consumer problem. Once you have a blocking queue, you can then easily wrap pushes to the queue in their own methods, making it feel like you're doing asynchronous calls to the worker thread.

Ivan
+1  A: 

The general approach to this kind of situation must be as follows:

  1. Decouple the remote source of the data with the "View".
  2. Make sure that the view is capable of updating dynamically when the underlying data changes. J2ME components do this by default - but if you author your own components, then you must take this into consideration.
  3. Run a separate thread and retrieve data.
  4. Notify the view whenever the data arrives.

The working code for the MIDlet is posted below

import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.List;
import javax.microedition.midlet.*;


public class AsyncUI extends MIDlet implements SearchListener, CommandListener{
    Command CANCEL = new Command("STOP SEARCH",Command.CANCEL,1);
    Command EXIT = new Command("EXIT",Command.EXIT,2);
    SearchDevices finder = new SearchDevices();
    List deviceList = new List("List of Devices",List.IMPLICIT);

    public void startApp() {
        Display d = Display.getDisplay(this);
        finder.setSearchListener(this);
        deviceList.addCommand(CANCEL);
        deviceList.addCommand(EXIT);
        deviceList.setCommandListener(this);
        d.setCurrent(deviceList);
        new Thread( finder).start();
    }

    public void pauseApp() {
    }

    public void destroyApp(boolean unconditional) {
    }

    public void found( Device d){
        deviceList.append(d.getName(), null);
    }
    public void commandAction( Command c, Displayable d){

        if( c == CANCEL){
            finder.cancel();
            deviceList.removeCommand(CANCEL);
        }else if( c== EXIT ){
            finder.cancel(); /* Cleanup all resources before you quit*/
            notifyDestroyed();
        }
    }
}

class SearchDevices implements Runnable{

    private boolean keepFinding=true;
    private static final int LONG_TIME=10000; /* 10 Seconds */
    SearchListener l =null; /* Currently only one listener. There could be many*/

    public void run(){
        int i =0;
        System.out.println(" -- Started the activity of finding --");
        while( keepFinding){
            try {
                Thread.currentThread().sleep(LONG_TIME);
                Device d = new Device("Device Found "+i);
                i++;
                System.out.println(" -- Found the device --");
                l.found(d);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
        System.out.println(" -- No more devices will be found  --");
    }

    public void cancel(){ keepFinding = false; }
    public void setSearchListener( SearchListener l){this.l=l;}


}

    class Device{
        String name;
        public Device(String name ){ this.name = name; }
        public String getName(){ return name ; }
    }

    interface SearchListener{
        public void found( Device device);
    }
Kiran Kuppa