J2ME - 如何使线程返回一个值,并在该线程完成后,在其他操作中使用返回值?
Posted
技术标签:
【中文标题】J2ME - 如何使线程返回一个值,并在该线程完成后,在其他操作中使用返回值?【英文标题】:J2ME - How to make a thread return a value and after that thread is finished, use the return value in other operations? 【发布时间】:2014-06-23 01:14:58 【问题描述】:我有一些关于线程使用的问题,特别是当您必须等待线程完成才能执行其他操作时。
在我的应用程序中,我使用线程进行诸如 http 连接之类的操作,或者当我读取或写入 RecordStore 时。
例如,在我用于初始化线程的以下类中,我使用名为 HttpQueryCustomers 的方法从 Web 服务中检索一些客户。
public class thrLoadCustomers implements Runnable
private RMSCustomer mRMSCustomer;
private String mUrl;
public thrLoadCustomers(RMSCustomer rmsCust, String url)
mRMSCustomer = rmsCust;
mUrl = url;
public void run()
String jsonResultados = "";
try
jsonResultados = HttpQueryCustomers();
catch (IOException ex)
//How to show a message from here??
catch (SecurityException se)
//How to show a message here??
catch (NullPointerException npe)
//How to show a message from here??
if (!jsonResultados.equals(""))
try
mRMSCustomer.save(jsonResultados);
catch (RecordStoreException ex)
//How to show a message from here???
public String HttpQueryCustomers() throws IOException,SecurityException,NullPointerException
StringBuffer stringBuffer = new StringBuffer();
HttpConnection hc = null;
InputStream is = null;
System.out.println(mUrl);
try
hc = (HttpConnection) Connector.open(mUrl);
if (hc.getResponseCode() == HttpConnection.HTTP_OK)
is = hc.openInputStream();
int ch;
while ((ch = is.read()) != -1)
stringBuffer.append((char) ch);
finally
is.close();
hc.close();
String jsonData = stringBuffer.toString();
return jsonData.toString();
请注意,在上面的类中,我传递了一个名为 rmsCust 的参数,类型为 RMSCustomer
RMSCustomer 是我用来处理与 RMS 相关的所有操作的类:
public class RMSCustomer
private String mRecordStoreName;
private Customer[] mCustomerList;
public RMSCustomer(String recordStoreName)
mRecordStoreName = recordStoreName;
public Customer[] getCustomers()
return mCustomerList;
public Customer get(int index)
return mCustomerList[index];
public void save(String data) throws RecordStoreException,JSONException,NullPointerException
RecordStore rs = null;
int idNuevoRegistro;
String stringJSON;
try
rs = RecordStore.openRecordStore(mRecordStoreName, true);
JSONArray js = new JSONArray(data);
//Set the size of the array
mCustomerList = new Customer[js.length()];
for (int i = 0; i < js.length(); i++)
JSONObject jsObj = js.getJSONObject(i);
stringJSON = jsObj.toString();
idNuevoRegistro = addRecord(stringJSON, rs);
//Add a new Customer to the array
mCustomerList[i] = initializeCustomer(stringJSON, idNuevoRegistro);
finally
if (rs != null)
rs.closeRecordStore();
public int addRecord(String stringJSON, RecordStore rs) throws JSONException,RecordStoreException
byte[] raw = stringJSON.getBytes();
int idNuevoRegistro = rs.addRecord(raw, 0, raw.length);
return idNuevoRegistro;
public Customer initializeCustomer(String stringJSON, int idRecord) throws JSONException
Customer c = new Customer();
JSONObject jsonObj = new JSONObject(stringJSON);
// Set Customer properties
//...
return c;
该类用于显示客户列表,如您所见,它扩展了 List 类并接收客户数组作为参数。
public class ListCustomers extends List
private final Customer[] mData;
public static ListCustomers create(Customer[] data)
int i = 0;
for (; i < data.length; i++)
if (data[i] == null)
break;
String[] names = new String[i];
for (int j = 0; j < i; j++)
names[j] = data[j].name;
return new ListCustomers(names, data);
protected ListCustomers(String names[], Customer[] data)
super("List of Customer", IMPLICIT, names, null);
mData = data;
public Customer getSelectedObject()
return mData[this.getSelectedIndex()];
当我想显示客户列表时,这就是我从 MIDlet 调用线程的方式(使用所有 3 个之前的类):
private void showCustomerList(String url)
showWaitForm();
if (scrCustomerList == null)
rmsCustomers = new RMSCustomer("rmsCustomers");
thrLoadCustomers load = new thrLoadCustomers(rmsCustomers, url);
Thread t = new Thread(load);
t.start();
try
t.join();
catch (InterruptedException ex)
scrCustomerList = ListCustomers.create(rmsCustomers.getCustomers());
scrCustomerList.addCommand(cmdSelect);
scrCustomerList.addCommand(cmdBack);
scrCustomerList.setCommandListener(this);
mDisplay.setCurrent(scrCustomerList);
现在这是我遇到的问题:
showWaitForm()
不起作用(它设置了一个带有 Gauge 的表单作为
当前表格)
我不知道如何显示所有可能引发的异常
在 thrLoadCustomers 类中。
不知道用t.join()
是不是最好的选择
最后一个问题是关于book I'm reading 所说的:
线程尤其是稀缺商品。 MSA 规范要求必须允许应用程序创建 十个线程。仅仅因为你可以并不意味着你应该。一般来说, 尝试使用尽可能少的资源,以便您的应用程序将 尽可能顺利地运行
这是第一次使用线程,在我的应用程序中我可能有多达 10 个线程(类)。但是,我一次只会执行一次线程,我会违背前面的报价吗??
我希望我没有问太多问题。非常感谢您的帮助。
P.D 我在此处发布的大部分代码在 Gregor Ophey 的帮助下是不可能实现的
【问题讨论】:
J2ME 有 Future 和 Callable 吗?我要么向后移植这些概念,要么重新实现这些概念。 @DavidEhrmann 这些类不可用,我建议不要尝试编写 DIY 替代代码,除非您在并发编程方面非常有经验。 @MisterSmith 这些类的源代码可用。 【参考方案1】:问题 #1 是关于一个与线程无关的不同问题,并且显示的代码很少。我建议您发布一个新的专门问题,并对该问题进行适当的解释。
问题 #2 和 #3:您可以像这样定义包装类:
public class WSResult
private boolean success; //true if the WS call went ok, false otherwise
private String errorMessage; //Error message to display if the WS call failed.
private Object result; //Result, only if the WS call succeeded.
private boolean completed = false;
//TODO getter and setters methods here
在您的屏幕中,您可以创建一个结果实例并等待它:
WSResult result = new WSResult();
//Start thread here
new Thread(new LoadCustomersTask(result)).start();
//This is old school thread sync.
synchronized(result)
while(!result.isCompleted())
result.wait();
//Here the thread has returned, and we can diaplay the error message if any
if(result.isSuccess())
else
//Display result.getErrorMessage()
那么你的runnable会是这样的:
class LoadCustomersTask implements Runnable
private final WSResult result;
public LoadCustomersTask(WSResult res)
result = res;
public void run()
//Do the WS call
//If it went well
result.setSuccess(true);
result.setResult(jsonResultados);
//Else
result.setSuccess(false);
result.setErrorMessage("Your error message");
//In any case, mark as completed
result.setcompleted(true);
//And notify awaiting threads
synchronized(result)
result.notifyAll();
您也可以使用 thread.join 执行此操作,但等待/通知更好,因为您不会使屏幕依赖于 runnable 运行的特定线程。您可以在结果实例上等待/通知,如图所示,或者在 runnable 上等待/通知(如果它是供一次性使用的)。
问题 #4:是的,线程不能被滥用,特别是在 JavaME 中,程序通常在单核 CPU 中运行,频率约为 MHz。尽量不要同时运行超过 1-3 个线程。如果确实需要,请考虑使用单个线程来运行所有后台任务(阻塞队列)。
【讨论】:
拜托,你能给我解释一下这几行吗:synchronized(result)
和result.wait()
;
在我的回答中,我使用Object.wait/Object.notify
而不是Thread.sleep/Thread.interrupt
来协调线程。您可以阅读here 了解有关差异的更多信息,但想法是相同的:一个线程等待第二个线程完成。调用 wait/notify 时需要同步块,否则会抛出异常。
非常感谢@Mister Smith 我按照你的建议做了,现在我的代码更有条理了。以上是关于J2ME - 如何使线程返回一个值,并在该线程完成后,在其他操作中使用返回值?的主要内容,如果未能解决你的问题,请参考以下文章