J2ME - 如何让线程返回一个值,并在该线程完成后,在其他操作中使用返回值?

时间:2014-06-23 01:14:59

标签: multithreading java-me

我对线程的使用有一些疑问,特别是当你必须等待线程完成以便你可以执行其他操作时。

在我的应用程序中,我使用线程进行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;
    }


}

此类用于显示客户列表,如您所见,它扩展了列表类,并接收一组Customers作为参数。

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

现在我遇到的问题是:

  1. showWaitForm()不起作用(它设置一个带有Gauge的表单作为 目前的表格)
  2. 我不知道如何显示可能引发的所有异常 在 thrLoadCustomers 类中。
  3. 我不知道使用t.join()是否是最佳选择
  4. 最后一个问题是book I'm reading所说的内容:
  5.   

    特别是线程可能是稀缺商品。 MSA   规范要求必须允许应用程序创建   十个帖子。只是因为你不能意味着你应该这样做。一般来说,   尽量使用尽可能少的资源,以便您的应用程序能够使用   尽可能顺利地运行

    这是第一次使用线程,而在我的应用程序中,我可能最多有10个线程(类)。但是,我当时只会执行一次线程,我是否会反对前一个引用所说的内容?

    我希望我不会问太多问题。非常感谢你的帮助。

    P.D在Gregor Ophey

    的帮助下,我在这里发布的大部分代码都无法实现

1 个答案:

答案 0 :(得分:2)

问题#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执行此操作,但是wait / notify更好,因为您不会使屏幕依赖于运行runnable的特定线程。您可以在结果实例上等待/通知,如图所示,或者如果只是一次性使用,可以在runnable上等待。

问题#4:是的线程不得滥用,特别是在JavaME中,程序通常在单核CPU中运行,频率为MHz。尽量不要同时运行超过1-3个线程。如果您确实需要,请考虑使用单个线程来运行所有后台任务(阻塞队列)。