我一直试图通过试验/错误以及研究来解决这个问题......但我似乎无法理解它。我对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方法,那就太棒了。就像我说的,我尝试了很多东西,做了大量的研究,只是无法想出任何有用的东西。
答案 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线程进行交互,因此这些是您可以绘制到屏幕的唯一位置(即填充适配器并使其无效以便重绘)