Android AsyncTask无法直接访问UI

时间:2012-09-21 17:11:40

标签: android android-asynctask

我是Android新手。我有一个正在下载URL内容的AsyncTask。 我不希望AsyncTask直接操作UI,并希望它将它作为可重用的代码片段,所以我把它放在一个自己的文件中,它返回一个字符串。 问题是返回发生在AsyncTask完成之前(即使我使用.excecute()的.get()),所以我什么也得不回来。 这是我现在的情况:

package com.example.mypackage;

import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.ExecutionException;

import android.os.AsyncTask;

public class URLContent {
private String content = "default value";

public String getContent(String URL){
    try {
        new getAsyncContent().execute(URL).get();
    } catch (InterruptedException e) {
        content = e.getMessage();
    } catch (ExecutionException e) {
        content = e.getMessage();
    }
    return content;
}

private class getAsyncContent extends AsyncTask<String, Integer, String>
{
    @Override
    protected void onPostExecute(String result) {
         content = result;
    }

    @Override
    protected String doInBackground(String... urls) {
        try{
            return URLResponse(urls[0]);
        } catch (Exception e){
            return e.getMessage();
        }

    }
}

private String IStoString(InputStream stream) throws IOException, UnsupportedEncodingException {
    try {
        return new java.util.Scanner(stream, "UTF-8").useDelimiter("\\A").next();
    } catch (java.util.NoSuchElementException e) {
        return "";
    }
}

private String URLResponse(String URLToget) throws IOException {
    InputStream is = null;

    try {
        URL url = new URL(URLToget);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setReadTimeout(10000 /* milliseconds */);
        conn.setConnectTimeout(15000 /* milliseconds */);
        conn.setRequestMethod("GET");
        conn.setDoInput(true);
        conn.connect();
        is = conn.getInputStream();
        // Convert the InputStream into a string
        String contentAsString = IStoString(is);
        return contentAsString;
    } finally {
        if (is != null) {
            is.close();
        } 
    }
}
}

解决这个问题的最佳方法是什么,以便我的主线程以某种方式取回结果? 我在一些文章中提到了事件和回调。这是最好的方式..?

4 个答案:

答案 0 :(得分:2)

不要get()。只需在doInBackground方法中对URL执行结果进行任何逻辑处理即可。从中你不必返回任何东西。在您的特定情况下,问题是在结果传递之前立即执行get()

这是异步执行,您无法对其应用线性逻辑

答案 1 :(得分:2)

感谢您的帮助。我将尝试通过Alex扩展asyncTask类的解决方案,听起来像一个干净的解决方案。

我设法通过在类中使用AsyncTask的接口并在主类上添加事件监听器来完成我的尝试。 所以获取内容的课程现在看起来像这样:

package com.example.test;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;

import android.os.AsyncTask;

public class URLContent {
public void getContent(String URL){
    new getAsyncContent().execute(URL);
}

public interface OnContentDownloadedListener{
    public abstract void onContentDownloaded(String content);
}
private OnContentDownloadedListener contentDownloadedListener = null;
public void setOnContentDownloadedListener(OnContentDownloadedListener content){
    contentDownloadedListener = content;
}

private class getAsyncContent extends AsyncTask<String, Integer, String>
{
    @Override
    protected void onPostExecute(String result) {
        contentDownloadedListener.onContentDownloaded(result);
    }

    @Override
    protected String doInBackground(String... urls) {
        try{
            return URLResponse(urls[0]);
        } catch (Exception e){
            return e.getMessage();
        }
    }
}

private String IStoString(InputStream stream) throws IOException, UnsupportedEncodingException {
    try {
        return new java.util.Scanner(stream, "UTF-8").useDelimiter("\\A").next();
    } catch (java.util.NoSuchElementException e) {
        return "";
    }
}

private String URLResponse(String URLToget) throws IOException {
    InputStream is = null;

    try {
        URL url = new URL(URLToget);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setReadTimeout(10000 /* milliseconds */);
        conn.setConnectTimeout(15000 /* milliseconds */);
        conn.setRequestMethod("GET");
        conn.setDoInput(true);
        conn.connect();
        is = conn.getInputStream();
        // Convert the InputStream into a string
        String contentAsString = IStoString(is);
        return contentAsString;
    } finally {
        if (is != null) {
            is.close();
        } 
    }
}
}

然后在我的主类中,我只有一个处理UI更新的事件监听器

urlContent.setOnContentDownloadedListener(new URLContent.OnContentDownloadedListener(){
            public void onContentDownloaded(String content){
//update UI or do something with the data
}

答案 2 :(得分:1)

使用AsyncTask的结果更新UI是onPostExecute()的主要目的。为了保持实现及其在UI中的使用方式,您的Activity可以扩展getAsyncContent类并覆盖onPostExecute()方法。此方法将在UI线程上执行。

答案 3 :(得分:1)

如果您不需要来自异步任务的UI更新,只需创建一个简单的线程即可完成。完成后,只需发送广播。

new Thread(new Runnable() {
    @Override
    public void run() {
        // Do the download here...
        ....
        // 
        sendBroadcast(some_intent);
}).start();