【问题标题】:Android issues with AsyncTask and InputStreamAsyncTask 和 InputStream 的 Android 问题
【发布时间】:2012-10-11 21:45:03
【问题描述】:

很长一段时间以来,我一直在尝试自己解决这个问题。通过反复试验和研究,但我似乎无法弄清楚。我对 Async 和网络连接以及 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 方法,那就太好了。就像我说的,我尝试了很多东西,做了很多研究,就是想不出任何有用的东西。

【问题讨论】:

    标签: android android-asynctask inputstream


    【解决方案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 内托

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

      • 我刚刚在主线程问题上遇到了网络操作。我确实必须研究更多关于异步和相关主题的信息。但我会考虑这些点。谢谢!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多