Android global variable in thread

2019-08-22 15:41发布

问题:

I have a problem. Here's my code:

public String getXmlFromUrl(String url) {
    String xml = null;

        new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                // defaultHttpClient
                DefaultHttpClient httpClient = new DefaultHttpClient();
                HttpGet httpGet = new HttpGet(url);

                HttpResponse httpResponse = httpClient.execute(httpGet);
                HttpEntity httpEntity = httpResponse.getEntity();
                xml = EntityUtils.toString(httpEntity);
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                } catch (ClientProtocolException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).run();
    // return XML
    return xml;
}

So, how can I use url in my Thread and how can I return xml?

Thank you for your help

回答1:

Android provides an AsyncTask, which perfectly fits your goal.

Example:

private class XMLTask extends AsyncTask<String, String, String> {
    @Override
    protected void onPreExecute() {
        // Do stuff
        // For example showing a Dialog to give some feedback to the user.
    }

    @Override
    protected String doInBackground(.. parameters..) {
        try {
            // defaultHttpClient
            DefaultHttpClient httpClient = new DefaultHttpClient();
            HttpGet httpGet = new HttpGet(url);

            HttpResponse httpResponse = httpClient.execute(httpGet);
            HttpEntity httpEntity = httpResponse.getEntity();
            xml = EntityUtils.toString(httpEntity);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } 
        return xml;
    }

    @Override
    protected void onPostExecute(String xml) {
        // If you have created a Dialog, here is the place to dismiss it.
        // The `xml` that you returned will be passed to this method
        xml.Dowhateveryouwant

        }
    }
}


回答2:

Make url final to use it.

If you don't mind blocking until the other thread is completed, make xml into an AtomicReference, and after calling Thread.start() (note you should 'not' call Thread.run() - that will not spawn another thread), use some synchronization tool (such as a CountdownLatch) to wait until the thread finishes before returning xml.

But if you don't mind blocking, why not just execute the code without a separate thread? If you can't block, then you can't return the xml value - you must change the design, perhaps executing an AsyncTask and providing the result asynchronously.



回答3:

You can mark your URL as final and use it within your Runnable like so:

public String getXmlFromUrl(final String url) {
    // ...
}

You probably want to define a stateless callback method or class that you can invoke to handle your XML response. You would call it like so:

xml = EntityUtils.toString(httpEntity);
handleXmlResponse(xml);

You could define the method handleXmlResponse as a private method of the class that contains the getXmlFromUrl method if you like.

One thing you might want to consider is using the Executors class to get a newSingleThreadExecutor and pass your Runnable to that instead of creating a new Thread every time you want to fetch some XML:

https://developer.android.com/reference/java/util/concurrent/Executors.html#newSingleThreadExecutor%28%29

Here's an example:

ExecutorService mThreadPool = Executors.newSingleThreadExecutor();
public String getXmlFromUrl(String url) {
    String xml = null;

        // Note the change here. Everything else remains the same.
        mThreadPool.execute(new Runnable() {

            @Override
            public void run() {
                try {
                // defaultHttpClient
                DefaultHttpClient httpClient = new DefaultHttpClient();
                HttpGet httpGet = new HttpGet(url);

                HttpResponse httpResponse = httpClient.execute(httpGet);
                HttpEntity httpEntity = httpResponse.getEntity();
                xml = EntityUtils.toString(httpEntity);
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                } catch (ClientProtocolException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    // return XML
    return xml;
}


回答4:

2 things:

  • This method is a synchronous call so better to use an AsyncTask.
  • Use Thread.start() to launch a thread.