如何正确设置AsyncTask以将下载与UI线程分开?

时间:2011-12-12 20:56:29

标签: android listview android-asynctask

我的应用程序发出HTTP请求以检索XML文件,然后将其转换为ListView。 问题是,当打开包含该列表的View时,应用程序冻结几秒钟,同时内容被下载并解析并转换到ListView。 (但它确实有效)。

我试图在后台线程中实现AsyncTask(请参阅下面的代码)来处理,但是我的实现导致应用程序冻结的时间比以前长得多。

这涉及三个类:MainActivity类; ListViewer类;和XMLhelper类。 MainActivity只包含一个用于调用ListViewer的Button。 ListViewer应该是UI线程。 XMLhelper包含用于发出HttpClient请求的函数。

ListViewer.java(简要):

public class ListViewer extends ListActivity {

    private ArrayList<HashMap<String, String>> xmlList;
    private String server;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.list_view);

        xmlList = new ArrayList<HashMap<String, String>>();
        server = "http://www.myserver.com/xml";
        getXMLList();
    }

    public void getXMLList() {
        Document xmlDocument = XMLhelper.getXMLDocument(server);
        int numResults = XMLfunctions.numResults(xmlDocument);
        if (numResults <= 0) {
            Toast.makeText(this, "No results found.", Toast.LENGTH_LONG).show();
            finish();
        }

        NodeList nodes = xmlDocument.getElementsByTagName("result");
        for (int i=0; i<nodes.getLength(); i++) {
            HashMap<String, String> map = new HashMap<String, String>();
            Element e = (Element)nodes.item(i);
            map.put(...); //code omitted
            xmlList.add(map);
        }

        ListAdapter adapter = new SimpleAdapter(this, xmlList,
            R.layout.list_view_row,
            new String[] {...},
            new int[] {...});
        setListAdapter(adapter);
    }
}

XMLhelper.java(简要):

public class XMLhelper {
    public static class DownloadContentTask extends AsyncTask<String, Void, String> {
        DownloadContentTask(String... URLs) {
            this.execute(URLs);
        }
        @Override
        protected String doInBackground(String... URLs) {
            String xml = null;
            try {
                DefaultHttpClient httpClient = new DefaultHttpClient();
                HttpPost httpPost = new HttpPost(URLs[0]);
                HttpResponse httpResponse = httpClient.execute(httpPost);
                HttpEntity httpEntity = httpResponse.getEntity();
                xml = EntityUtils.toString(httpEntity);
            } catch (...) {
                xml = "..."; //all exceptions are caught
            }
            return xml;
        }
    }

    public static Document getXMLDocument(String server) {
        DownloadContentTask xmlTask = new DownloadContentTask(new String[] { server });
        String xml = "";
        try {
            xml = xmlTask.get();
        } catch (...) {
            //print errors
        }
        return XMLfromString(xml);
    }

    public static Document XMLfromString(String xml) { ... }
    public final static String getElementValue(Node elem) { ... }
    public static int numResults(Document doc) { ... }
    public static String getValue(Element item, String str) { ... }
}

我打算这样做,以便当从MainActivity调用ListViewer时,ListView未填充但是UI立即显示,然后在下载和解析内容后,ListView就会更新。

我做错了什么?

2 个答案:

答案 0 :(得分:1)

非常简单,请查看get()方法文档:

  

如果需要等待计算完成,然后检索其结果。

通过在get()中调用getXMLDocument来阻止当前线程(UI线程)直到,异步任务就完成了。

异步任务应该自己进行更新,在UI线程中调用它们,而不是从UI线程将信息返回给调用者。

你应该一直阅读文档;)

答案 1 :(得分:1)

您可以覆盖AsyncTask中的onPostExecute方法,此方法在UI线程上运行,并在doInBackground()方法完成后调用。从onPostExecute()方法获得的参数是doInBackground()方法的返回值