| Reply | « Previous Thread | Next Thread » |
|
Hello,
I am trying to create a test midlet that performs httpconnections in a new, separate thread (so it will run on my 7650). The main thread waits for the new thread to finish, and the main thread then displays a results screen. Initially, the new thread dd seem do its stuff, but then the main thread would not resume and execute any code after the wait() line. But now I've been playing around with it so much I am getting an IllegalMonitorStateException. Here is my code. Any help would be greatly appreciated. Thanks, James import javax.microedition.midlet.*; import javax.microedition.lcdui.*; import java.io.*; import javax.microedition.io.*; public class OtaThreadTestMIDlet extends MIDlet implements CommandListener { private Command commandExit, commandOK, commandHome; // The exit command private Display display; // The display for this MIDlet private Form f; private String[] urls, results; private HttpConnection con; private InputStream in; private Gauge g; private Object mutex = new Object(); private OtaThread otaT; private String[] resultsStrings; public OtaThreadTestMIDlet() { System.err.println("now in OtaThreadTestMIDlet constructor"); display = Display.getDisplay(this); commandExit = new Command("Exit", Command.SCREEN, 2); commandOK = new Command("OK", Command.BACK, 0); commandHome = new Command("Home", Command.BACK, 0); urls = new String[2]; urls[0] = ""; //enter first url here urls[1] = ""; //enter second url here, etc } public void startApp() { System.err.println("now in startApp()"); createInstructionsScreen(); } private void createInstructionsScreen() { System.err.println("now in createInstructionsScreen()"); f = new Form("Instructions!"); f.append("Press OK to get data ota from:"); for (int i = 0; i < urls.length; i++) { f.append("\n\n"); f.append(urls[i]); } f.addCommand(commandOK); f.addCommand(commandExit); f.setCommandListener(this); display.setCurrent(f); } public void pauseApp() { } public void destroyApp(boolean unconditional) { } public void commandAction(Command c, Displayable s) { if (c == commandOK) { Form resultsForm = new Form("Results"); resultsForm.setCommandListener(this); otaT = new OtaThread(urls, mutex, this); otaT.setPriority(Thread.MAX_PRIORITY); //(This line doesn't give the desired effect) //synchronized (this){ //synchronized (mutex) { synchronized (this) { otaT.start(); try { wait(); //mutex.wait(); } catch(InterruptedException ie) { System.err.println("InterruptedException: " + ie.getMessage()); } } resultsForm = new Form("Results"); resultsForm.append("And the results are:"); for (int i = 0; i < results.length; i++) { resultsForm.append("\n\n"); resultsForm.append(results[i]); } resultsForm.addCommand(commandExit); resultsForm.addCommand(commandHome); display.setCurrent(resultsForm); } else if (c == commandHome) { createInstructionsScreen(); } else if (c == commandExit) { destroyApp(false); notifyDestroyed(); } } public class OtaThread extends Thread { private String[] urls; private Form resultsForm; private OtaThreadTestMIDlet o; private Object mutex; //Constructor OtaThread(String[] urls, Object mutex, OtaThreadTestMIDlet o) { this.urls = urls; this.mutex = mutex; this.o = o; } public void run() { synchronized (o) { try { resultsStrings = getStringsFromUrls(urls); } catch(Exception e) { System.err.println("Exception: " + e.toString() + " - " + e.getMessage()); e.printStackTrace(); } o.notify(); //mutex.notify(); } } private String[] getResultsStrings() { return resultsStrings; } //This method takes an array of urls and returns an array of strings (obtained from the urls) private String[] getStringsFromUrls(String[] urls) throws Exception {; for (int i = 0; i < urls.length; i++) { System.err.println("urls[" + i + "]: " + urls[i]); } String[] returnStringArray = new String[urls.length]; StringBuffer sBReturn; Form progressForm = new Form("Please wait"); g = new Gauge("Contacting Server", false, 100, 0); //g is the progress gauge progressForm.append(g); display.setCurrent(progressForm); try{ for (int u = 0; u < urls.length; u++) { sBReturn = new StringBuffer(); con = (HttpConnection)Connector.open(urls[u]); in = con.openInputStream(); if (g.getValue() == 0) g.setValue(100 / (urls.length + 1)); int len = (int)con.getLength(); if (len > 0) { byte[] bytes = new byte[len]; int actual = in.read(bytes); returnStringArray[u] = new String(bytes); } else { int ch; while ((ch = in.read()) != -1) { sBReturn.append((char)ch); } returnStringArray[u] = sBReturn.toString(); } g.setValue(100 * (u + 2) / (urls.length + 1)); } //next url } finally { try { if (in != null) in.close(); if (con != null) con.close(); } catch (IOException ioe) { System.err.println("IOException: " + ioe.getMessage()); } } return returnStringArray; } } } |
|
do you not have to declare the commandAction method as synchronized as well?
public synchronized void commandAction(Command c, Displayable s) { |
|
Tried it but no joy. Thanks tho.
|
|
It is not a problem obtaining the lock. You execute both the wait and the notify in a synchronized block, both synchronized on the one and only MIDlet instance.
However, you seem to call the 'wait()' method while executing the commandAction. This holds the processing of not only your commandAction method, but may hold ALL event processing of your midlet-application. In your OtaThread, you create a Form. I don't know too much about how the J2ME of the 7650 dispatches events; If it uses only one thread per application for event-dispatching (regardless of the thread creating the displayable), your midlet is entered in a deadlock as soon as you create the Form in your OtaThread (since the wait() method of the main thread has stopped the event-dispatching). Try to remove the Form with the progress-bar (remove *all* User interface code) and see what happens. Since you call wait() in your main thread anyway, why not just obtain the URLs data in your main thread? -- Anton |
|
What you are doing doesn't make any sense: you're starting a new Thread, and then wait for it to finish. Why start a new Thread then? The point of Threads is that you can increase concurrency by doing multiple things at once. But you're doing only one thing at a time, so instead of creating the new Thread, you could just as well (better) just call the run method directly. (and call it something else probably)
However, that wouldn't be good in this case, because you don't want to hold up the event thread. Event methods like commandAction(), paint(), etc. should return as quickly as possible. Any long term operations should be performed in another Thread. Which you did.. but you didn't see the point, because you're waiting for it to finish in the same event Thread. So the whole purpose of spawning a new Thread is gone. One way to fix all this would be to do the long-term processing in another Thread; *not* wait for it to finish, and then use a listener approach to notify the Form to display the results. To see what i'm talking about, read the following article, which describes a very similar problem, and solution: http://today.java.net/pub/a/today/2003/10/24/swing.html Have fun! -- Niek
Last edited by niekvs : 2004-01-22 at 01:33.
|
|
Here is a similar example as the one that Niekvs gave (using listeners). But this one is for MIDlets. You can almost copy and paste code in this example:
http://www.forum.nokia.com/main/1,65...ml&fileID=2642 -- Anton. |
|
Cheers guys, and thanks for the links.
The reason I need a new thread for the http stuff owes to a bug on the 7650. If you try and do the httpconnection stuff in the main thread, the midlet hangs, so that's why the new thread. Incidentally, I also tried using Thread's join() method instead of wait() and notify(), but that performed really poorly on the 7650. I will gives those links a read. Many thanks, James |
|
Hi,
unefortunately I can't find this article (http://www.forum.nokia.com/main/1,6...tml&fileID=2642) on forum.nokia. Is it still available? Or could someone send it to me (inselschaaf@gmx.net). Many thanks, Heike |
| Reply | « Previous Thread | Next Thread » |
| Thread Tools | Search this Thread |
|---|---|