2

我是安卓新手。我有一个正在下载 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

4 回答 4

2

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

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

于 2012-09-21T17:28:18.943 回答
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
}
于 2012-09-22T14:23:34.437 回答
1

Updating UI with the results of AsyncTask is the main purpose of onPostExecute(). To keep the implementation and the way it's used in UI separate, your Activity can extend your getAsyncContent class and override the onPostExecute() method. This method will be executed on UI thread.

于 2012-09-21T17:29:17.193 回答
1

如果您不需要异步任务中的 UI 更新,只需创建一个简单的线程来执行这些操作。完成后,只需发送一个广播。

new Thread(new Runnable() {
    @Override
    public void run() {
        // Do the download here...
        ....
        // 
        sendBroadcast(some_intent);
}).start();
于 2012-09-21T17:43:37.997 回答