Message passing to asynchronus working thread in J

2019-06-11 11:55发布

问题:

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?

回答1:

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);
    }


回答2:

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.