How to get a string back from AsyncTask?

AndroidStringAndroid Asynctask

Android Problem Overview


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

Android Solutions


Solution 1 - Android

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

Solution 2 - Android

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.

Solution 3 - Android

If the user clicks the button, then has to wait for the content, what do they do meanwhile?

Why not do this:

  1. User clicks button.
  2. You check for connectivity. If the user isn't connected to the Internet, tell them.
  3. You start an IntentService by sending an Intent to send the HTTP request.
  4. When the request finishes, you post a notification.
  5. 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.

Solution 4 - Android

  1. Get the context in the constructor like this:

    public GetDataTask(Context context) {}

  2. Create an Interface with the method:

    void onDataRetrieved(String data);

  3. Implement the Interface in the class from where you are creating the Task object (e.g. MainActivity)

  4. Cast the Context to the Interface and call the onDataRetrieved Method

Solution 5 - Android

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;
        }
    }
}

Solution 6 - Android

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);
    }
}

Solution 7 - Android

This ONE LINER worked for me:

String result = MyasyncTask.execute(type, usrPhoneA, usrPWDA).get();

Solution 8 - Android

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPaulView Question on Stackoverflow
Solution 1 - AndroidK-balloView Answer on Stackoverflow
Solution 2 - AndroidpawelziebaView Answer on Stackoverflow
Solution 3 - AndroidJoe MalinView Answer on Stackoverflow
Solution 4 - AndroidMatthias HerrmannView Answer on Stackoverflow
Solution 5 - AndroidGeneView Answer on Stackoverflow
Solution 6 - AndroidDragasView Answer on Stackoverflow
Solution 7 - AndroidfrancisqueinsView Answer on Stackoverflow
Solution 8 - AndroidisabsentView Answer on Stackoverflow