0

很长一段时间以来,我一直试图自己解决这个问题。通过反复试验和研究,但我似乎无法弄清楚。我对异步和网络连接以及 stuch 非常糟糕,所以这可能是我正在寻找的简单的东西。无论如何...我将粘贴一些相关的代码示例和解释。

我的问题的快速背景。我正在为我的应用程序使用 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 方法,那就太好了。就像我说的,我尝试了很多东西,做了很多研究,就是想不出任何有用的东西。

4

2 回答 2

1

关键是,您不了解 asynctask 的工作原理!

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

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

在 doInBackground 上,您正确地调用了方法 retrieveStream,但您对流没有做任何事情。因此,您必须处理流,然后将其返回。正如你所说,你期待一个 JSON,我假设你会收到一个字符串,所以你的 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();
            }
        }

你可以像以前一样打电话。

清楚吗?需要更多解释吗?

[]s 内托

于 2012-10-11T22:07:03.537 回答
0

你看到什么样的行为是出乎意料的。通过扫描您的代码,它看起来可能已编译并运行,但我猜您的 ListAdapter 永远不会使用新数据进行更新(即您可能试图在 ListView 或 GridView 中显示结果,但没有显示任何内容)。那是对的吗?还是您仍然收到主线程上的网络错误?

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

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

于 2012-10-11T22:08:45.907 回答