Skip to main content

I am lost in the multithreading problem based on the NetBeans Mobility Pack

2 replies [Last post]
gaolin_bei
Offline
Joined: 2006-11-12

Now I am lost in the multithreading problem based on the NetBeans Mobility Pack's Visual MIDlet:
What's my design intention is that developing a mobile cilent connection to a web server Tomcat Servlet, I know based on the Mobility Pack's Visual MIDlet i can drag components to the Flow Deginer and by this way i can easily construct the mobile GUI,and then i can design the logic code in other place,am i right?Now I will show my idea by the following code,and i wish to get some one's help:

Firstly,my package is like this:

-com.swc.se.SeClient.logic
+SeClientLoginThread.java (deal with the connection and so on)

-com.swc.se.SeClient.UI
+SeClientUI.java (just the GUI)

SeClientUI.java is a Visual MIDlet,and i drag loginForm[Form] to the Flow Designer,then change part of the SeClientUI as following:
(There are username and password fileds in the login form,and after filling in them the tomcat servlet will verify the user information by returning a String "success" or "failure")

private Thread loginThread; //only the login
private Thread registThread; //future add the regist and so on

/** Called by the system to indicate that a command has been invoked on a particular

displayable.
* @param command the Command that ws invoked
* @param displayable the Displayable on which the command was invoked
*/
public void commandAction(Command command, Displayable displayable) {
if (displayable == login) {
if (command == okCommand1) {
String username=get_username().getString();
String password=get_password().getString();
SeClientLoginThread seClientLoginThread=new SeClientLoginThread
(username,password);
loginThread=new Thread(seClientLoginThread);
loginThread.start();
String isLoginSuc=seClientLoginThread.getIsLoginSuc();
//if the user information is right:
if(isLoginSuc.equals("success")){
getDisplay().setCurrent(get_search());
}

else{
getDisplay().setCurrent(get_failureAlert());
}
// Insert post-action code here
} else if (command == registCommand) {
// Insert pre-action code here
getDisplay().setCurrent(get_regist());
// Insert post-action code here
}
}
// Insert global post-action code here
}

And here i separate the logic code SeClientLoginThread from the GUI code

SeClientUI,following is the SeClientLoginThread code:

public class SeClientLoginThread implements Runnable{
final static String loginURL=
"http://localhost:8080/ServiceEngine/mobile/ConsumerLogin";
String isLoginSuc="success";
String username="";
String password="";
/** Creates a new instance of SeClientLogin */
public SeClientLoginThread(String username,String password) {
this.username=username;
this.password=password;
}
public void run() {
DataInputStream ds=null;
HttpConnection hc =null;
DataOutputStream dos = null;
DataInputStream dis = null;
try {
hc = (HttpConnection)Connector.open(loginURL);
hc.setRequestMethod(HttpConnection.POST);
hc.setRequestProperty("IF-Modified-Since","15 Oct 2003 08:47:14 GMT");
hc.setRequestProperty("User-Agent","Profile/MIDP-1.0 Configuration/CLDC-1.0");
hc.setRequestProperty("Content-Language","en-CA");
hc.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
hc.setRequestProperty("Connection","Keep-Alive");
dos=hc.openDataOutputStream();
dos.writeUTF(username);
dos.writeUTF(password);
dos.flush();
dos.close();
ds = new DataInputStream(hc.openInputStream());
String returnStr="";
returnStr=ds.readUTF();
setIsLoginSuc(returnStr);
} catch (IOException ex) {
ex.printStackTrace();
}
}

public String getIsLoginSuc(){
return isLoginSuc;
}

public void setIsLoginSuc(String isLoginSuc){
this.isLoginSuc=isLoginSuc;
}

}

But now what the problem is that:

****
if (command == okCommand1) {
String username=get_username().getString();
String password=get_password().getString();
SeClientLoginThread seClientLoginThread=new SeClientLoginThread

(username,password);
loginThread=new Thread(seClientLoginThread);
loginThread.start();
String isLoginSuc=seClientLoginThread.getIsLoginSuc();

//if the user information is right:

if(isLoginSuc.equals("success")){
getDisplay().setCurrent(get_search());
}

else{
getDisplay().setCurrent(get_failureAlert());
}
********
the above code, after loginThread.start(),the main Thread(currentThred) id going on executing the following code ,so the other thread SeClientLoginThread's run method doesn't complete,that's to say
"
returnStr=ds.readUTF();
setIsLoginSuc(returnStr);

"
not executed before the main thread "seClientLoginThread.getIsLoginSuc();",so the return "String isLoginSuc" is always "success",how to solve this problem?

I am very sorry to say that i express my question in disorder,but i really wish somebody will help me out of this question.
Thank you!

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
stuart_marks
Offline
Joined: 2006-08-24

Hi, sorry for not responding earlier. I usually get email notification of forum postings, but for some reason only a few of them get cross-posted to emails, so I didn't see this until recently.

Also unfortunately, the Forum software doesn't format code very well. I had to copy your code into NetBeans in order to read it. :-)

Anyway, you have some typical threading issues here. There are two threads of concern here: (1) the event thread, which is the one that calls commandAction() in response to the user having pressed a button or whatever; and (2) what you're calling the login thread, which is created and started by when okCommand1 is invoked, and which talks over the network.

The problem is exactly as you observed: in the processing of okCommand1, the lines of code:

loginThread.start();
String isLoginSuc=seClientLoginThread.getIsLoginSuc();

are executed immediately in sequence, before the login thread has a chance to connect over the network and retrieve the information. Conceptually what you want to do is to wait until after the login thread has completed its work before calling getIsLoginSuc() and updating the UI with its results. But you don't actually want to wait in the middle of commandAction(), because that blocks the event thread. If you were to do this, the user interface would be frozen for as long as the login thread ran, and the user wouldn't be able to do anything, nor would the user have any indication that anything was happening. To avoid this problem, you have to return from the commandAction() method after starting up the login thread. But now, how do you call getIsLoginSuc() and update the UI after the login thread finishes?

Briefly, what you want to do is the following: (1) put up a "busy" alert of some sort to tell the user that work is in progress; (2) return from the commandAction() callback; (3) have the login thread do its work; (4) have the login thread provide progress indications to the UI; (5) allow for the user to cancel the operation; (6) when the login thread finishes, either have it update the UI itself, or (7) put the update-UI information into a Runnable and then have the event thread run that code by passing it to Display.callSerially().

Whew! That's a lot of stuff. It's probably too much to explain all of it here, but the good news is that I gave a presentation on exactly this topic at JavaOne 2003. Unfortunately the materials from this conference don't appear to be on-line in general... however, I did happen to find a copy of my slides on the net at this location:

http://galilei.aut.bme.hu/onlab/KirchTamas/Diploma/2037.pdf

The section of interest starts at slide 34, and there are code examples starting on slide 50 and interspersed through the rest of the presentation. They cover all of the issues I mention above.

Please let me know if you have further questions.

s'marks

tzurs
Offline
Joined: 2007-11-07

Hi,

I'm experiencing very odd threading behavior in both the wtk emulator (and others) and on real devices (tested many of them)
When I call HttpConnection.open (on a separate thread), ALL other threads are blocked until this method returns.
I've read your very very informative presentation mentioned in your reply and I believe everything I do is "on the spot" and yet I get this.
Are you familiar with this issue?
Is there any hint on how to workaround this?
thanx for any help!
--tzurs
poiuytrewq