问题
I have the following class:
public class getURLData extends AsyncTask<String, Integer, String>{
@Override
protected String doInBackground(String... params) {
String line;
try {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(params[0]);
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
line = EntityUtils.toString(httpEntity);
} catch (UnsupportedEncodingException e) {
line = "<results status=\"error\"><msg>Can't connect to server</msg></results>";
} catch (MalformedURLException e) {
line = "<results status=\"error\"><msg>Can't connect to server</msg></results>";
} catch (IOException e) {
line = "<results status=\"error\"><msg>Can't connect to server</msg></results>";
}
return line;
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
}
}
And I am trying to call it like this:
String output = null;
output = new getURLData().execute("http://www.domain.com/call.php?locationSearched=" + locationSearched);
But the output variable isn't getting data, instead I am getting an error:
Type mismatch: cannot convert from AsyncTask<String,Integer,String> to String
回答1:
The method execute
returns the AynscTask
itself, you need to call get
:
output =
new getURLData()
.execute("http://www.example.com/call.php?locationSearched=" + locationSearched)
.get();
This will start a new thread (via execute
) while blocking the current thread (via get
) until the work from the new thread has been finished and the result has been returned.
If you do this, you just turned your async task into a sync one.
However, the problem with using get
is that because it blocks, it needs to be called on a worker thread. However, AsyncTask.execute()
needs to be called on the main thread. So although this code could work, you may get some undesired results. I also suspect that get()
is under-tested by Google, and it is possible that they introduced a bug somewhere along the line.
Reference: AsyncTask.get
回答2:
I'd rather create callback than block UI thread. In your class create method which will be invoked when data arrive. For example:
private void setData(String data){
mTextView.setText(data);
}
Then in AsyncTask implement onPostExecute:
@Override
protected void onPostExecute(String result) {
setData(result);
}
And then somewhere in code just execute task:
new getURLData().execute(...
When task finishes setData is invoked and mTextView is filled.
AsyncTask.get() will blok your UI, so there is no reason to use AsyncTask.
回答3:
If the user clicks the button, then has to wait for the content, what do they do meanwhile?
Why not do this:
- User clicks button.
- You check for connectivity. If the user isn't connected to the Internet, tell them.
- You start an IntentService by sending an Intent to send the HTTP request.
- When the request finishes, you post a notification.
- The user clicks the notification, which returns to an Activity that can do the next step.
This allows the user to go off and do whatever while the request is being processed.
An IntentService runs in the background on its own thread. When it receives an Intent, it runs onHandleIntent(). When that method finishes, the Service is cached: it's not active, but it can re-start quickly when the next Intent arrives.
回答4:
Get the context in the constructor like this:
public GetDataTask(Context context) {}
Create an Interface with the method:
void onDataRetrieved(String data);
Implement the Interface in the class from where you are creating the Task object (e.g.
MainActivity
)Cast the Context to the Interface and call the onDataRetrieved Method
回答5:
In the following code, I get a String (directorName) back from AsyncTask.
public class GetDirector {
String id;
private String baseURL = "http://www.omdbapi.com/?i=";
private String finalURL = "";
String theDirector;
public GetDirector(String imdbID) throws ExecutionException, InterruptedException {
id= imdbID;
finalURL = baseURL + id + "&plot=full&r=json";
System.out.println("GetDirector. finalURL= " + finalURL);
theDirector = new GetDirectorInfo().execute().get();
}
public String getDirector (){
return theDirector;
}
private class GetDirectorInfo extends AsyncTask<Void, Void,String> {
@Override
protected String doInBackground(Void... params) {
String directorName = null;
ServiceHandler sh = new ServiceHandler();
// Making a request to url and getting response
String jsonStr = sh.makeServiceCall(finalURL, ServiceHandler.GET);
System.out.println("Act_DetailsPage. jsonStr= " + jsonStr);
if (jsonStr != null) {
try {
JSONObject everything = new JSONObject(jsonStr);
directorName = everything.getString(JSON_Tags.TAG_DIRECTOR);
System.out.println("directorName= "+ directorName);
} catch (JSONException e) {
e.printStackTrace();
}
} else {
System.out.println("Inside GetDirector. Couldn't get any data from the url");
}
return directorName;
}
}
}
回答6:
Add a context parameter to task's constructor which would refer to object where you'd store resulting data.
class PopulateArray extends AsyncTask<Integer, Integer, ArrayList<String>>
{
Context _context; // context may be what ever activity or object you want to store result in
PopulateArray(Context context)
{
_context = context;
}
@Override
protected ArrayList<String> doInBackground(Integer... integers)
{
ArrayList<String> data = new ArrayList<String>();
//manipulate
return data;
}
@Override
protected void onPostExecute(ArrayList<String> strings)
{
_context.setData(strings);
}
}
回答7:
This ONE LINER worked for me:
String result = MyasyncTask.execute(type, usrPhoneA, usrPWDA).get();
回答8:
The only way to send data from AsyncTask
to UI without pain is Otto or Event bus. Register a method which will handle a result under @Subscribe
annotation in UI and post
a message
with a result to it in onPostExecute
method of your AsyncTask
.
来源:https://stackoverflow.com/questions/10972114/how-to-get-a-string-back-from-asynctask