Question

I have an AsyncTask that takes in context (used onPostExecute) and runs doInBackground to return an ArrayList of objects from a server. When I execute this I can see that doInBackground runs fine, however it is not passing the result on to onPostExecute.

After much searching, I have yet to find an answer of how to return an ArrayList of objects in an AsyncTask.

This is the object I'm creating in doInBackground and using onPostExecute:

public class ServerTimeCard {

    public String eventNameInput;
    Boolean isLocation, isImage, isVoice;

    public ServerTimeCard(String eventNameInput, boolean isLocation, boolean isImage, boolean isVoice) {
        this.eventNameInput = eventNameInput;
        this.isLocation = isLocation;
        this.isImage = isImage;
        this.isVoice = isVoice;
    }

}

I'm executing the AsyncTask with new LoadFriendCards(context).execute(); in onCreate.

  • Expected Output: doInBackground should return an ArrayList to onPostExecute

  • Current Output: The ArrayList<ServerTimeCard> in onPostExecute has a size of zero when the same arraylist in doInBackground has a larger size.

The following is the AsyncTask code.

public class LoadFriendCards extends AsyncTask<Void, Void, ArrayList<ServerTimeCard>> {

            Context context;
            ArrayList<ServerTimeCard> result;

            public LoadFriendCards(Context context) {
                this.context = context;
            }

            @Override
            protected ArrayList<ServerTimeCard> doInBackground(Void... voids) {

                     result = new ArrayList<ServerTimeCard>();

                     // ...a bunch of data retrieval goes on here...    

                     // querying parse for object info
                     // adding a new object to the local ArrayList for all in db
                     for (String friend : friendsListNames) {
                          ParseQuery<ParseObject> query = ParseQuery.getQuery("TestObject");
                          query.whereEqualTo("accountName", friend+"@gmail.com");
                          query.findInBackground(new FindCallback<ParseObject>() {
                          public void done(List<ParseObject> objects, ParseException e) {
                          if (e == null) {

                               for (ParseObject cardInfo : objects) {

                                   ServerTimeCard item = new ServerTimeCard(
                                      cardInfo.getString("eventName"),
                                      cardInfo.getBoolean("isImage"),
                                      cardInfo.getBoolean("isImage"),
                                      cardInfo.getBoolean("isVoice"));

                                   result.add(item);


                        Log.e("New item called: ", String.valueOf(item.eventNameInput));
                        Log.e("New size of array...", String.valueOf(result.size()));

                    }

                } else {
                    Log.d("info", "Error: " + e.getMessage());
                }
            }
        });
    }

                // returning the new ArrayList<ServerTimeCard> to onPostExecute

                // PROBLEM: THE SIZE OF THE RESULT IS 0
                Log.e("Size of passing array", String.valueOf(result.size()));

                return result;
            }

            @Override
            protected void onPostExecute(ArrayList<ServerTimeCard> result) {

                // PROBLEM: This returns 0
                Log.e("Data list size: ", String.valueOf(result.size())); 

                // trying to use all objects in the arraylist here but it doesn't work
                // due to the size. Something isn't passing correctly.

            }
        }

Logcat output of Log.e: (which looks like it calls doInBackground, then onPostExecute, then doInBackground again)

E/Size of passing array﹕ 0
E/Data list size:﹕ 0
E/New item called:﹕ yah
E/New size of array...﹕ 1
E/New item called:﹕ lplokolol
E/New size of array...﹕ 2
E/New item called:﹕ It works
E/New size of array...﹕ 3

SOLVED: I originally thought I needed the AsyncTask but I ended up deleting it all and throwing all the code into a method in my Main class. I was running too many things at once in an asynctask and the structure was throwing data all over the place. Lesson learned: keep it simple.

Was it helpful?

Solution

Your issue is that you are using findInBackground for your query. That method is done in a background thread. So you're basically running an async task, within an async task.

  1. doInBackground
  2. findInBackground -> run asynchronously so code execute continues
  3. onPostExecute is called before your query finishes.
  4. The done call back is then called for your query to fill your list

So what you need to do instead is either use findInBackground outside of an AsyncTask (that method is intended to not be used in an AsyncTask) or use the find function.

OTHER TIPS

You're modifying result in an anonymous inner class. Your code there doesn't see the result you think it sees, but rather a closure. This is the root of the problem.

You are starting a background thread (your async task), and here you call query.findInBackground() multiple times which starts MORE background threads. This, however, isn't a problem.

You're getting problems because the AsyncTask is done before all the other threads it started have finished. You only know the other threads are done when each of their FindCallback's done() method is called.

If you want to know the correct size, you need to code it in a way so that you check the size in the last done() method.

You dont have to make doInBackground to return an arraylist which can be used in onPostExecute. Just return "ok" or "error". Declare and create a private arraylist as member of your ask. Then fill it in doInBackground and use it in onPostexecute.

An alternative and simpler way is to declare your doInBackground as List type. Here is my Example

    @Override
    protected  ArrayList<ServerTimeCard > doInBackground(String... urls) {
        // Perform the HTTP request for earthquake data and process the response.
        ArrayList<ServerTimeCard > result = QueryUtils.fetchTheData(urls[0]);
        return result;
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top