Frage

I am creating a j2me application which is interacting with a database on a server. Therefore I launch a thread to connect to the server. I handle all my command actions in a separate class which implements CommandListener.

When I try to get the response the server returned I get an empty String. I have tried waiting for the thread that connects to the server to return but this makes the application unresponsive.

Below is the code I am using.

//my network worker class.
public class NetworkConnector implements Runnable {
    //constructor
    public NetworkConnector(String url){
       //url =>server url to connect to.
       Thread thread = new Thread(this);
       thread.start();
    }

    private String serverReply="";
    private String url="

    //method to connect to the server and return the 
    //response from the server.
    public String sendData(String serverUrl) {

      //open streams to connect to the Server.
      httpConn = (HttpConnection)  
      Connector.open(serverUrl,Connector.READ_WRITE, true);
      httpConn.setRequestMethod(HttpConnection.GET);

      inStream = httpConn.openInputStream();
      int read;
      while ((read = inStream.read()) != -1) {
        sb.append((char) read);
      }

      return sb.toString();
   }


   public String getServerReply() {
     //serverReply is a class variable.
     return serverReply;
   }

   public void run(){
      //call the send method that connects to the server.
       serverResponse = sendData(Url);
   }

} //end of connector class.

// this class is where all my Command Actions are
//implemented. 
public class CommandActionController implements
CommandListener, DataReceiver {

public void commandAction(Command cmd, Displayable d) {
   //networkMgr => is the worker class that makes
   //connection to the server.
   networkMgr = new NetworkConnector("http://localhost
   /JsonPhp/login.php?uname=" + loginUserInfo.userName +
   "&passwd=" + loginUserInfo.password);

   //here am getting the response from the server.
   String serverResponse = networkMgr.getServerReply();

   //at this point the ServerReponse String is Empty =>
   //yet the server is supposed to return some String.
   System.out.println("xxxxxxxxxxxxxxxxxx
   ServerResponse =" + serverResponse);
   }

   }//end of CommandListener class.
War es hilfreich?

Lösung

Your expectations about serverResponse value are wrong; it can be empty at the moment when you attempt to obtain it in commandAction with the code snippet in the question.

In order to get non-empty value, you need to redesign method NetworkConnector.getServerReply() to make it properly wait until thread finishes and server response is indeed obtained.

If you do that, however, you will also have to redesign CommandActionController to keep user interface responsive - your testing with "waiting for the thread that connects to the server" has shown just that.

Redesigned code should just launch the server connect thread and exit the commandAction as soon as possible (possibly changing to some "wait screen" to let user see what happens). Next screen update should be triggered only after server response is obtained.

Consider studying a tutorial specifically targeted on explaining how to properly design this kind applications - Networking, User Experience, and Threads:

This article explains how your MIDlet can make network connections without compromising your user interface. It includes six iterative examples that illustrate multithreaded networking and the use of a wait screen...

Andere Tipps

Here is how I'd do without java.util.concurrent:

Result handleRequest(){
    final String url = // get url
    Work work = new Work(url):
    Thread t = new Thread(work);
    t.start();
    // do other stuff
    if(t.isAlive()){
        // still running
    }
    // this waits until the work is done
    // and it will be safe to access work.result after
    // this call has returned.
    t.join(); 
    return work.result;
}

and then

class Work implements Runnable{
    final String url;
    Result result;
    public void run(){
        this.result = // do your network stuff
    }
}

You shouldn't start a thread in the constructor. Also, runnable are meant to be passed to threads. The easiest (and the "proper") way of doing this would be as follows:

  1. Implement a Callable instead of a Runnable.
  2. Use a ExecutorService instead of a Thread
  3. Use Future object to do the processing asynchronously/be responsive to user

Here is a simple example.

class Stuff {
    final ExecutorService exec = 
                 Executors.newCachedExecutorService(// please see doc);
    Result process(String url){
        Future<Result> future = exec.submit(new Work(url));
        // do some other stuff
        if(future.isDone()){
            // return result?
        }
        return future.get(); // this call will wait until result is available
    }
} 

and then

class Work implements Callable<Result> {
    final String url;
    Result call() throws Exception {
        // do your network stuff here
        return result;
    }
}

See documentation of java.util.concurrent.ExecutorService.submit(), java.util.concurrent.Future and java.util.concurrent.Callable for details.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top