Android与AsyncTask和InputStream有关

时间:2012-10-11 21:45:04

标签: android android-asynctask inputstream

我一直试图通过试验/错误以及研究来解决这个问题......但我似乎无法理解它。我对Async和网络连接非常糟糕,所以我可能看起来很简单。无论如何......我会粘贴一些相关的代码示例和解释。

我的问题的快速背景。我正在为我的应用程序使用Rotten Tomatoes API,并使用GSON来解析他们的数据。我最初的目标是2.3,这很好。然后我决定支持ICS,当然遇到了“UI线程上的无网络操作” - 所以我开始深入研究AsyncTask。

这是我的InputStream方法:

private InputStream retrieveStream(String url) {

    DefaultHttpClient client = new DefaultHttpClient();

    HttpGet getRequest = new HttpGet(url);

    try {

        HttpResponse getResponse = client.execute(getRequest);
        final int statusCode = getResponse.getStatusLine().getStatusCode();

        if (statusCode != HttpStatus.SC_OK) {
            Log.w(getClass().getSimpleName(),
                    "Error " + statusCode + " for URL " + url);
            return null;
        }

        HttpEntity getResponseEntity = getResponse.getEntity();
        return getResponseEntity.getContent();
    }
    catch (IOException e) {
        getRequest.abort();
        Log.w(getClass().getSimpleName(), "Error for URL " + url, e);
    }

    return null;
}

在我的主要活动中哪个工作正常,现在在尝试将其“转换”为AsyncTask时给了我一些问题。我一直这样称呼它:

InputStream source = retrieveStream( url parameter );

然后我尝试将该方法移动到我的AsyncTask类中,并调用它:

private PerformMovieSearch performSearch = new PerformMovieSearch(this);
InputStream source = performSearch.retrieveStream(movieQueryUrl);

但是这并没有削减它,仍然得到关于在UI上执行网络操作的错误。我需要弄清楚的是如何从AsyncTask调用'retrieveStream'我猜。目前该课程如下:

package net.neonlotus.ucritic;

[imports]

public class PerformMovieSearch extends AsyncTask<String, Void, String> {

private final Context context;
private ProgressDialog progressDialog;


public PerformMovieSearch(Context context){
    this.context = context;
}


@Override
protected String doInBackground(String... urls) {
    retrieveStream(urls[0]);

    return null;

}

@Override
protected void onPreExecute() {
    progressDialog= ProgressDialog.show(context, "Please Wait","Searching movies", true);

}


@Override
protected void onPostExecute(String result) {
    super.onPostExecute(result);
    progressDialog.dismiss();

    MyActivity.mListAdapter.notifyDataSetChanged();
}

public InputStream retrieveStream(String url) {

    DefaultHttpClient client = new DefaultHttpClient();
    HttpGet getRequest = new HttpGet(url);

    try {
        HttpResponse getResponse = client.execute(getRequest);
        final int statusCode = getResponse.getStatusLine().getStatusCode();

        if (statusCode != HttpStatus.SC_OK) {
            Log.w(getClass().getSimpleName(),
                    "Error " + statusCode + " for URL " + url);
            return null;
        }

        HttpEntity getResponseEntity = getResponse.getEntity();
        return getResponseEntity.getContent();
    } catch (IOException e) {
        getRequest.abort();
        Log.w(getClass().getSimpleName(), "Error for URL " + url, e);
    }

    return null;
}

}

“doinbackground”是需要改变的......但我似乎无法找到一种直接的方法来使其正常工作。我正在使用

执行
new PerformMovieSearch(this).execute(movieQueryUrl);

我知道这很多东西,可能令人困惑......但如果有人知道如何异步地执行retrieveStream方法,那就太棒了。就像我说的,我尝试了很多东西,做了大量的研究,只是无法想出任何有用的东西。

2 个答案:

答案 0 :(得分:1)

重点是,你不明白asynctask如何运作!

您必须阅读指南流程和主题:http://developer.android.com/guide/components/processes-and-threads.html

但好吧,让我试着帮助你。

在doInBackground上,您正在调用方法retrieveStream,但是您对该流没有任何作用。因此,您必须处理流然后返回它。如你所说,你期待一个JSON,我假设你会收到一个String,所以你的retrieveStream的代码应该是这样的:

public String retrieveStream(String url) {

    DefaultHttpClient client = new DefaultHttpClient();
    HttpGet getRequest = new HttpGet(url);

    try {
        HttpResponse getResponse = client.execute(getRequest);
        final int statusCode = getResponse.getStatusLine().getStatusCode();

        if (statusCode != HttpStatus.SC_OK) {
            Log.w(getClass().getSimpleName(),
                    "Error " + statusCode + " for URL " + url);
            return null;
        }

        HttpEntity getResponseEntity = getResponse.getEntity();
        String jsonString = EntityUtils.toString(getResponseEntity);
        return jsonString;
    } catch (IOException e) {
        getRequest.abort();
        Log.w(getClass().getSimpleName(), "Error for URL " + url, e);
    }

    return null;
}

看看我将返回类型更改为String。也许,您应该将名称更改为retrieveMoviesJSON或类似的内容。

你应该将你的AsyncTask更改为:

class PerformMovieSearch AsyncTask<String, Void, ArrayList<Movie>>() {

            @Override
            protected void onPreExecute() {
                progressDialog= ProgressDialog.show(context, "Please Wait","Searching movies", true);
            }

            @Override
            protected ArrayList<Movie> doInBackground(String... params) {
                String moviesJson = retrieveStream[params[0]];
                JSONObject moviesJson = new JSONObject(moviesJson);
                ArrayList<Movie> movies = new ArrayList<Movie>();
                /*
                 * Do your code to process the JSON and create an ArrayList of films.
                 * It's just a suggestion how to store the data.
                 */
                return movies;
            }

            protected void onPostExecute(ArrayList<Movie> result) {
                progressDialog.dismiss();
                //create a method to set an ArrayList in your adapter and set it here.
                MyActivity.mListAdapter.setMovies(result);
                MyActivity.mListAdapter.notifyDataSetChanged();
            }
        }

你可以按照你的方式打电话。

清楚吗?需要更多解释?

[]中 内托

答案 1 :(得分:0)

您认为这是出乎意料的行为。从扫描你的代码,它看起来可能编译和运行,但我猜你的ListAdapter永远不会更新新数据(即你可能试图在ListView或GridView中显示结果,但没有任何东西出现)。那是对的吗?或者您仍然在主线程上出现网络错误?

您正在使用HTTP客户端检索数据,然后不对其执行任何操作。解决问题的一种方法是构建代码,使得: 1)扩展AsyncTask的类有一个构造函数,它接受一个ListAdapter对象
2)您的主Activity将创建AsyncTask的实例并传入对其ListAdapter对象的引用
3)您的doInBackground方法将处理所有网络活动并返回结果(您从Web服务中提取的数据),以便它传递给onPostExecute方法
4)在onPostExecute中,您将拥有从doInBackground返回的数据,并且您将拥有构造函数中提供的ListAdapter,因此解析数据,填充ListAdapter并使其无效以便重新绘制列表。 BR />

请记住,AsyncTask允许您在onPreExecute和onPostExecute方法中与UI线程进行交互,因此这些是您可以绘制到屏幕的唯一位置(即填充适配器并使其无效以便重绘)